Fix rubocop offenses - Requires Ruby 3.1+

This commit is contained in:
Sebastian Serth
2022-11-25 10:53:14 +01:00
parent bdf474e684
commit 574e99eddd
93 changed files with 315 additions and 315 deletions

View File

@ -115,16 +115,16 @@ class ApplicationController < ActionController::Base
redirect_back fallback_location: :root, allow_other_host: false, alert: message redirect_back fallback_location: :root, allow_other_host: false, alert: message
end end
end end
format.json { render json: {error: message}, status: status } format.json { render json: {error: message}, status: }
end end
end end
private :render_error private :render_error
def switch_locale(&action) def switch_locale(&)
session[:locale] = sanitize_locale(params[:custom_locale] || params[:locale] || session[:locale]) session[:locale] = sanitize_locale(params[:custom_locale] || params[:locale] || session[:locale])
locale = session[:locale] || I18n.default_locale locale = session[:locale] || I18n.default_locale
Sentry.set_extras(locale: locale) Sentry.set_extras(locale:)
I18n.with_locale(locale, &action) I18n.with_locale(locale, &)
end end
private :switch_locale private :switch_locale

View File

@ -60,7 +60,7 @@ module CodeOcean
yield if block_given? yield if block_given?
path = options[:path].try(:call) || @object path = options[:path].try(:call) || @object
respond_with_valid_object(format, notice: t('shared.object_created', model: @object.class.model_name.human), respond_with_valid_object(format, notice: t('shared.object_created', model: @object.class.model_name.human),
path: path, status: :created) path:, status: :created)
else else
filename = "#{@object.path || ''}/#{@object.name || ''}#{@object.file_type.try(:file_extension) || ''}" filename = "#{@object.path || ''}/#{@object.name || ''}#{@object.file_type.try(:file_extension) || ''}"
format.html do format.html do

View File

@ -11,7 +11,7 @@ module CommonBehavior
notice = result if result.present? notice = result if result.present?
end end
path = options[:path].try(:call) || @object path = options[:path].try(:call) || @object
respond_with_valid_object(format, notice: notice, path: path, status: :created) respond_with_valid_object(format, notice:, path:, status: :created)
else else
respond_with_invalid_object(format, template: :new) respond_with_invalid_object(format, template: :new)
end end
@ -51,7 +51,7 @@ module CommonBehavior
notice = result if result.present? notice = result if result.present?
end end
path = options[:path] || @object path = options[:path] || @object
respond_with_valid_object(format, notice: notice, path: path, status: :ok) respond_with_valid_object(format, notice:, path:, status: :ok)
else else
respond_with_invalid_object(format, template: :edit) respond_with_invalid_object(format, template: :edit)
end end

View File

@ -16,14 +16,14 @@ module FileConversion
path = File.dirname(file['name']).sub(%r{^(?>\./|\.)}, '').presence path = File.dirname(file['name']).sub(%r{^(?>\./|\.)}, '').presence
file_type = all_file_types.detect {|ft| ft.file_extension == extension } || FileType.new(file_extension: extension) file_type = all_file_types.detect {|ft| ft.file_extension == extension } || FileType.new(file_extension: extension)
CodeOcean::File.new( CodeOcean::File.new(
name: name, name:,
path: path, path:,
size: file['size'], size: file['size'],
owner: file['owner'], owner: file['owner'],
group: file['group'], group: file['group'],
permissions: file['permissions'], permissions: file['permissions'],
updated_at: file['modificationTime'], updated_at: file['modificationTime'],
file_type: file_type file_type:
) )
end end
[augment_files_for_download(files), directories] [augment_files_for_download(files), directories]

View File

@ -124,7 +124,7 @@ module RedirectBehavior
session: session.to_hash, session: session.to_hash,
submission: @submission.inspect, submission: @submission.inspect,
params: params.as_json, params: params.as_json,
current_user: current_user, current_user:,
lti_exercise_id: session[:lti_exercise_id], lti_exercise_id: session[:lti_exercise_id],
lti_parameters_id: session[:lti_parameters_id] lti_parameters_id: session[:lti_parameters_id]
) )

View File

@ -115,8 +115,8 @@ class ExecutionEnvironmentsController < ApplicationController
end end
render locals: { render locals: {
working_time_statistics: working_time_statistics, working_time_statistics:,
user_statistics: user_statistics, user_statistics:,
} }
end end
@ -132,7 +132,7 @@ class ExecutionEnvironmentsController < ApplicationController
params[:execution_environment] params[:execution_environment]
.permit(:docker_image, :editor_mode, :file_extension, :file_type_id, :help, :indent_size, :memory_limit, :cpu_limit, :name, .permit(:docker_image, :editor_mode, :file_extension, :file_type_id, :help, :indent_size, :memory_limit, :cpu_limit, :name,
:network_enabled, :privileged_execution, :permitted_execution_time, :pool_size, :run_command, :test_command, :testing_framework) :network_enabled, :privileged_execution, :permitted_execution_time, :pool_size, :run_command, :test_command, :testing_framework)
.merge(user_id: current_user.id, user_type: current_user.class.name, exposed_ports: exposed_ports) .merge(user_id: current_user.id, user_type: current_user.class.name, exposed_ports:)
end end
end end
private :execution_environment_params private :execution_environment_params

View File

@ -128,15 +128,15 @@ class ExercisesController < ApplicationController
status: 'success', status: 'success',
message: t('exercises.export_codeharbor.successfully_exported', id: @exercise.id, title: @exercise.title), message: t('exercises.export_codeharbor.successfully_exported', id: @exercise.id, title: @exercise.title),
actions: render_to_string(partial: 'export_actions', actions: render_to_string(partial: 'export_actions',
locals: {exercise: @exercise, exported: true, error: error}), locals: {exercise: @exercise, exported: true, error:}),
} }
@exercise.save @exercise.save
else else
render json: { render json: {
status: 'fail', status: 'fail',
message: t('exercises.export_codeharbor.export_failed', id: @exercise.id, title: @exercise.title, error: error), message: t('exercises.export_codeharbor.export_failed', id: @exercise.id, title: @exercise.title, error:),
actions: render_to_string(partial: 'export_actions', actions: render_to_string(partial: 'export_actions',
locals: {exercise: @exercise, exported: true, error: error}), locals: {exercise: @exercise, exported: true, error:}),
} }
end end
end end
@ -146,7 +146,7 @@ class ExercisesController < ApplicationController
return render json: {}, status: :unauthorized if user.nil? return render json: {}, status: :unauthorized if user.nil?
uuid = params[:uuid] uuid = params[:uuid]
exercise = Exercise.find_by(uuid: uuid) exercise = Exercise.find_by(uuid:)
return render json: {uuid_found: false} if exercise.nil? return render json: {uuid_found: false} if exercise.nil?
return render json: {uuid_found: true, update_right: false} unless ExercisePolicy.new(user, exercise).update? return render json: {uuid_found: true, update_right: false} unless ExercisePolicy.new(user, exercise).update?
@ -163,7 +163,7 @@ class ExercisesController < ApplicationController
return render json: {}, status: :unauthorized if user.nil? return render json: {}, status: :unauthorized if user.nil?
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
exercise = ::ProformaService::Import.call(zip: tempfile, user: user) exercise = ::ProformaService::Import.call(zip: tempfile, user:)
exercise.save! exercise.save!
render json: {}, status: :created render json: {}, status: :created
end end
@ -185,7 +185,7 @@ class ExercisesController < ApplicationController
private :user_from_api_key private :user_from_api_key
def user_by_codeharbor_token(api_key) def user_by_codeharbor_token(api_key)
link = CodeharborLink.find_by(api_key: api_key) link = CodeharborLink.find_by(api_key:)
link&.user link&.user
end end
@ -394,8 +394,8 @@ class ExercisesController < ApplicationController
def working_times def working_times
working_time_accumulated = @exercise.accumulated_working_time_for_only(current_user) working_time_accumulated = @exercise.accumulated_working_time_for_only(current_user)
working_time_75_percentile = @exercise.get_quantiles([0.75]).first working_time_75_percentile = @exercise.get_quantiles([0.75]).first
render(json: {working_time_75_percentile: working_time_75_percentile, render(json: {working_time_75_percentile:,
working_time_accumulated: working_time_accumulated}) working_time_accumulated:})
end end
def intervention def intervention
@ -404,7 +404,7 @@ class ExercisesController < ApplicationController
render(json: {success: 'false', error: "undefined intervention #{params[:intervention_type]}"}) render(json: {success: 'false', error: "undefined intervention #{params[:intervention_type]}"})
else else
uei = UserExerciseIntervention.new( uei = UserExerciseIntervention.new(
user: current_user, exercise: @exercise, intervention: intervention, user: current_user, exercise: @exercise, intervention:,
accumulated_worktime_s: @exercise.accumulated_working_time_for_only(current_user) accumulated_worktime_s: @exercise.accumulated_working_time_for_only(current_user)
) )
uei.save uei.save
@ -483,7 +483,7 @@ class ExercisesController < ApplicationController
checked_tags = checked_exercise_tags.collect(&:tag).to_set checked_tags = checked_exercise_tags.collect(&:tag).to_set
unchecked_tags = Tag.all.to_set.subtract checked_tags unchecked_tags = Tag.all.to_set.subtract checked_tags
@exercise_tags = checked_exercise_tags + unchecked_tags.collect do |tag| @exercise_tags = checked_exercise_tags + unchecked_tags.collect do |tag|
ExerciseTag.new(exercise: @exercise, tag: tag) ExerciseTag.new(exercise: @exercise, tag:)
end end
end end
@ -522,7 +522,7 @@ class ExercisesController < ApplicationController
end end
render locals: { render locals: {
user_statistics: user_statistics, user_statistics:,
} }
end end

View File

@ -72,7 +72,7 @@ class ExternalUsersController < ApplicationController
end end
render locals: { render locals: {
statistics: statistics, statistics:,
} }
end end

View File

@ -41,7 +41,7 @@ class FileTypesController < ApplicationController
end end
def set_editor_modes def set_editor_modes
@editor_modes = Dir.glob('vendor/assets/javascripts/ace/mode-*.js').sort.map do |filename| @editor_modes = Dir.glob('vendor/assets/javascripts/ace/mode-*.js').map do |filename|
name = filename.gsub(%r{\w+/|mode-|.js$}, '') name = filename.gsub(%r{\w+/|mode-|.js$}, '')
[name, "ace/mode/#{name}"] [name, "ace/mode/#{name}"]
end end

View File

@ -28,7 +28,7 @@ class FlowrController < ApplicationController
# once the programming language model becomes available, the language name can be added to the query to # once the programming language model becomes available, the language name can be added to the query to
# produce more relevant results # produce more relevant results
query = attributes.map(&:value).join(' ') query = attributes.map(&:value).join(' ')
{submission: submission, error: error, attributes: attributes, query: query} {submission:, error:, attributes:, query:}
end end
# Always return JSON # Always return JSON

View File

@ -151,7 +151,7 @@ class InternalUsersController < ApplicationController
checked_study_groups = checked_study_group_memberships.collect(&:study_group).sort.to_set checked_study_groups = checked_study_group_memberships.collect(&:study_group).sort.to_set
unchecked_study_groups = StudyGroup.all.order(name: :asc).to_set.subtract checked_study_groups unchecked_study_groups = StudyGroup.all.order(name: :asc).to_set.subtract checked_study_groups
@study_group_memberships = checked_study_group_memberships + unchecked_study_groups.collect do |study_group| @study_group_memberships = checked_study_group_memberships + unchecked_study_groups.collect do |study_group|
StudyGroupMembership.new(user: @user, study_group: study_group) StudyGroupMembership.new(user: @user, study_group:)
end end
end end

View File

@ -26,14 +26,14 @@ class LiveStreamsController < ApplicationController
runner = Runner.for(current_user, @execution_environment) runner = Runner.for(current_user, @execution_environment)
fallback_location = shell_execution_environment_path(@execution_environment) fallback_location = shell_execution_environment_path(@execution_environment)
privileged = params[:sudo] || @execution_environment.privileged_execution? privileged = params[:sudo] || @execution_environment.privileged_execution?
send_runner_file(runner, desired_file, fallback_location, privileged: privileged) send_runner_file(runner, desired_file, fallback_location, privileged:)
end end
private private
def send_runner_file(runner, desired_file, redirect_fallback = root_path, privileged: false) def send_runner_file(runner, desired_file, redirect_fallback = root_path, privileged: false)
filename = File.basename(desired_file) filename = File.basename(desired_file)
send_stream(filename: filename, type: 'application/octet-stream', disposition: 'attachment') do |stream| send_stream(filename:, type: 'application/octet-stream', disposition: 'attachment') do |stream|
runner.download_file desired_file, privileged_execution: privileged do |chunk, overall_size, _content_type| runner.download_file desired_file, privileged_execution: privileged do |chunk, overall_size, _content_type|
unless response.committed? unless response.committed?
# Disable Rack::ETag, which would otherwise cause the response to be cached # Disable Rack::ETag, which would otherwise cause the response to be cached

View File

@ -15,7 +15,7 @@ class RemoteEvaluationController < ApplicationController
else else
201 201
end end
render json: result, status: status render json: result, status:
end end
# POST /submit # POST /submit
@ -29,7 +29,7 @@ class RemoteEvaluationController < ApplicationController
status = result[:status] status = result[:status]
end end
render json: result, status: status render json: result, status:
end end
def try_lti def try_lti
@ -62,7 +62,7 @@ class RemoteEvaluationController < ApplicationController
def create_and_score_submission(cause) def create_and_score_submission(cause)
validation_token = remote_evaluation_params[:validation_token] validation_token = remote_evaluation_params[:validation_token]
if (remote_evaluation_mapping = RemoteEvaluationMapping.find_by(validation_token: validation_token)) if (remote_evaluation_mapping = RemoteEvaluationMapping.find_by(validation_token:))
@submission = Submission.create(build_submission_params(cause, remote_evaluation_mapping)) @submission = Submission.create(build_submission_params(cause, remote_evaluation_mapping))
@submission.calculate_score @submission.calculate_score
else else

View File

@ -146,7 +146,7 @@ class SubmissionsController < ApplicationController
end end
else else
Rails.logger.info("Unknown command from client: #{event[:cmd]}") Rails.logger.info("Unknown command from client: #{event[:cmd]}")
Sentry.set_extras(event: event) Sentry.set_extras(event:)
Sentry.capture_message("Unknown command from client: #{event[:cmd]}") Sentry.capture_message("Unknown command from client: #{event[:cmd]}")
end end
rescue JSON::ParserError => e rescue JSON::ParserError => e
@ -183,19 +183,19 @@ class SubmissionsController < ApplicationController
exit_statement = exit_statement =
if @testrun[:output].empty? && exit_code.zero? if @testrun[:output].empty? && exit_code.zero?
@testrun[:status] = :ok @testrun[:status] = :ok
t('exercises.implement.no_output_exit_successful', timestamp: l(Time.zone.now, format: :short), exit_code: exit_code) t('exercises.implement.no_output_exit_successful', timestamp: l(Time.zone.now, format: :short), exit_code:)
elsif @testrun[:output].empty? elsif @testrun[:output].empty?
@testrun[:status] = :failed @testrun[:status] = :failed
t('exercises.implement.no_output_exit_failure', timestamp: l(Time.zone.now, format: :short), exit_code: exit_code) t('exercises.implement.no_output_exit_failure', timestamp: l(Time.zone.now, format: :short), exit_code:)
elsif exit_code.zero? elsif exit_code.zero?
@testrun[:status] = :ok @testrun[:status] = :ok
"\n#{t('exercises.implement.exit_successful', timestamp: l(Time.zone.now, format: :short), exit_code: exit_code)}" "\n#{t('exercises.implement.exit_successful', timestamp: l(Time.zone.now, format: :short), exit_code:)}"
else else
@testrun[:status] = :failed @testrun[:status] = :failed
"\n#{t('exercises.implement.exit_failure', timestamp: l(Time.zone.now, format: :short), exit_code: exit_code)}" "\n#{t('exercises.implement.exit_failure', timestamp: l(Time.zone.now, format: :short), exit_code:)}"
end end
stream = @testrun[:status] == :ok ? :stdout : :stderr stream = @testrun[:status] == :ok ? :stdout : :stderr
send_and_store client_socket, {cmd: :write, stream: stream, data: "#{exit_statement}\n"} send_and_store client_socket, {cmd: :write, stream:, data: "#{exit_statement}\n"}
if exit_code == 137 if exit_code == 137
send_and_store client_socket, {cmd: :status, status: :out_of_memory} send_and_store client_socket, {cmd: :status, status: :out_of_memory}
@testrun[:status] = :out_of_memory @testrun[:status] = :out_of_memory
@ -307,8 +307,8 @@ class SubmissionsController < ApplicationController
exercise_id = @submission.exercise_id exercise_id = @submission.exercise_id
remote_evaluation_mapping = RemoteEvaluationMapping.create( remote_evaluation_mapping = RemoteEvaluationMapping.create(
user: user, user:,
exercise_id: exercise_id, exercise_id:,
study_group_id: session[:study_group_id] study_group_id: session[:study_group_id]
) )
@ -370,7 +370,7 @@ class SubmissionsController < ApplicationController
testrun = Testrun.create!( testrun = Testrun.create!(
file: @file, file: @file,
passed: @testrun[:passed], passed: @testrun[:passed],
cause: cause, cause:,
submission: @submission, submission: @submission,
exit_code: @testrun[:exit_code], # might be nil, e.g., when the run did not finish exit_code: @testrun[:exit_code], # might be nil, e.g., when the run did not finish
status: @testrun[:status] || :failed, status: @testrun[:status] || :failed,
@ -379,7 +379,7 @@ class SubmissionsController < ApplicationController
waiting_for_container_time: @testrun[:waiting_for_container_time] waiting_for_container_time: @testrun[:waiting_for_container_time]
) )
TestrunMessage.create_for(testrun, @testrun[:messages]) TestrunMessage.create_for(testrun, @testrun[:messages])
TestrunExecutionEnvironment.create(testrun: testrun, execution_environment: @submission.used_execution_environment) TestrunExecutionEnvironment.create(testrun:, execution_environment: @submission.used_execution_environment)
end end
def send_hints(tubesock, errors) def send_hints(tubesock, errors)
@ -430,10 +430,10 @@ class SubmissionsController < ApplicationController
parsed[:stream] = parsed[:stream].to_sym if parsed.key? :stream parsed[:stream] = parsed[:stream].to_sym if parsed.key? :stream
parsed parsed
else else
{cmd: :write, stream: stream, data: data} {cmd: :write, stream:, data:}
end end
rescue JSON::ParserError rescue JSON::ParserError
{cmd: :write, stream: stream, data: data} {cmd: :write, stream:, data:}
end end
def augment_files_for_download(files) def augment_files_for_download(files)

View File

@ -58,7 +58,7 @@ class SubscriptionsController < ApplicationController
study_group_id = current_user.try(:current_study_group_id) study_group_id = current_user.try(:current_study_group_id)
if params[:subscription].present? if params[:subscription].present?
params[:subscription].permit(:request_for_comment_id, :subscription_type).merge(user_id: current_user_id, params[:subscription].permit(:request_for_comment_id, :subscription_type).merge(user_id: current_user_id,
user_type: current_user_class_name, study_group_id: study_group_id, deleted: false) user_type: current_user_class_name, study_group_id:, deleted: false)
end end
end end
private :subscription_params private :subscription_params

View File

@ -82,7 +82,7 @@ class UserExerciseFeedbacksController < ApplicationController
else else
implement_exercise_path(@exercise) implement_exercise_path(@exercise)
end end
update_and_respond(object: @uef, params: uef_params, path: path) update_and_respond(object: @uef, params: uef_params, path:)
else else
flash.now[:danger] = t('shared.message_failure') flash.now[:danger] = t('shared.message_failure')
redirect_back fallback_location: user_exercise_feedback_path(@uef) redirect_back fallback_location: user_exercise_feedback_path(@uef)
@ -126,15 +126,15 @@ class UserExerciseFeedbacksController < ApplicationController
user_id = current_user.id user_id = current_user.id
user_type = current_user.class.name user_type = current_user.class.name
latest_submission = Submission latest_submission = Submission
.where(user_id: user_id, user_type: user_type, exercise_id: exercise_id) .where(user_id:, user_type:, exercise_id:)
.order(created_at: :desc).final.first .order(created_at: :desc).final.first
authorize(latest_submission, :show?) authorize(latest_submission, :show?)
params[:user_exercise_feedback] params[:user_exercise_feedback]
.permit(:feedback_text, :difficulty, :exercise_id, :user_estimated_worktime) .permit(:feedback_text, :difficulty, :exercise_id, :user_estimated_worktime)
.merge(user_id: user_id, .merge(user_id:,
user_type: user_type, user_type:,
submission: latest_submission, submission: latest_submission,
normalized_score: latest_submission&.normalized_score) normalized_score: latest_submission&.normalized_score)
end end

View File

@ -8,7 +8,7 @@ module ActionCableHelper
ActionCable.server.broadcast( ActionCable.server.broadcast(
"la_exercises_#{exercise_id}_channel_study_group_#{submission.study_group_id}", "la_exercises_#{exercise_id}_channel_study_group_#{submission.study_group_id}",
type: :rfc, type: :rfc,
id: id, id:,
html: ApplicationController.render(partial: 'request_for_comments/list_entry', html: ApplicationController.render(partial: 'request_for_comments/list_entry',
locals: {request_for_comment: self}) locals: {request_for_comment: self})
) )

View File

@ -53,9 +53,9 @@ module ApplicationHelper
ActionController::Base.helpers.sanitize Kramdown::Document.new(markdown).to_html ActionController::Base.helpers.sanitize Kramdown::Document.new(markdown).to_html
end end
def row(options = {}, &block) def row(options = {}, &)
tag.div(class: 'attribute-row row') do tag.div(class: 'attribute-row row') do
label_column(options[:label]) + value_column(options[:value], &block) label_column(options[:label]) + value_column(options[:value], &)
end end
end end

View File

@ -11,7 +11,7 @@ module AuthenticatedUrlHelper
COOKIE_EXPIRATION = 30.seconds COOKIE_EXPIRATION = 30.seconds
def sign(url, object) def sign(url, object)
payload = {object_id: object.id, object_type: object.class.name, url: url, exp: TOKEN_EXPIRATION.from_now.to_i} payload = {object_id: object.id, object_type: object.class.name, url:, exp: TOKEN_EXPIRATION.from_now.to_i}
token = JWT.encode payload, TOKEN_SECRET, TOKEN_ALGORITHM token = JWT.encode payload, TOKEN_SECRET, TOKEN_ALGORITHM
add_query_parameters(url, {TOKEN_PARAM => token}) add_query_parameters(url, {TOKEN_PARAM => token})
@ -58,7 +58,7 @@ module AuthenticatedUrlHelper
def prepare_short_living_cookie(value) def prepare_short_living_cookie(value)
{ {
value: value, value:,
expires: COOKIE_EXPIRATION.from_now, expires: COOKIE_EXPIRATION.from_now,
httponly: true, httponly: true,
same_site: :strict, same_site: :strict,

View File

@ -9,9 +9,9 @@ class AuthenticationToken < ApplicationRecord
def self.generate!(user, study_group) def self.generate!(user, study_group)
create!( create!(
shared_secret: SecureRandom.hex(32), shared_secret: SecureRandom.hex(32),
user: user, user:,
expire_at: 7.days.from_now, expire_at: 7.days.from_now,
study_group: study_group study_group:
) )
end end
end end

View File

@ -40,7 +40,7 @@ module CodeOcean
scope :visible, -> { where(hidden: false) } scope :visible, -> { where(hidden: false) }
ROLES.each do |role| ROLES.each do |role|
scope :"#{role}s", -> { where(role: role) } scope :"#{role}s", -> { where(role:) }
end end
scope :teacher_defined_assessments, -> { where(role: %w[teacher_defined_test teacher_defined_linter]) } scope :teacher_defined_assessments, -> { where(role: %w[teacher_defined_test teacher_defined_linter]) }

View File

@ -48,7 +48,7 @@ class ExecutionEnvironment < ApplicationRecord
def to_json(*_args) def to_json(*_args)
{ {
id: id, id:,
image: docker_image, image: docker_image,
prewarmingPoolSize: pool_size, prewarmingPoolSize: pool_size,
cpuLimit: cpu_limit, cpuLimit: cpu_limit,

View File

@ -79,7 +79,7 @@ class Exercise < ApplicationRecord
end end
def time_maximum_score(user) def time_maximum_score(user)
submissions.where(user: user).where("cause IN ('submit','assess')").where.not(score: nil).order('score DESC, created_at ASC').first.created_at submissions.where(user:).where("cause IN ('submit','assess')").where.not(score: nil).order('score DESC, created_at ASC').first.created_at
rescue StandardError rescue StandardError
Time.zone.at(0) Time.zone.at(0)
end end
@ -251,7 +251,7 @@ class Exercise < ApplicationRecord
end end
end end
{user_progress: user_progress, additional_user_data: additional_user_data} {user_progress:, additional_user_data:}
end end
def get_quantiles(quantiles) def get_quantiles(quantiles)
@ -495,7 +495,7 @@ class Exercise < ApplicationRecord
description = task_node.xpath('p:description/text()')[0].content description = task_node.xpath('p:description/text()')[0].content
self.attributes = { self.attributes = {
title: task_node.xpath('p:meta-data/p:title/text()')[0].content, title: task_node.xpath('p:meta-data/p:title/text()')[0].content,
description: description, description:,
instructions: description, instructions: description,
} }
task_node.xpath('p:files/p:file').all? do |file| task_node.xpath('p:files/p:file').all? do |file|
@ -508,7 +508,7 @@ class Exercise < ApplicationRecord
content: file.xpath('text()').first.content, content: file.xpath('text()').first.content,
read_only: false, read_only: false,
hidden: file_class == 'internal', hidden: file_class == 'internal',
role: role, role:,
feedback_message: role == 'teacher_defined_test' ? feedback_message_nodes.first.content : nil, feedback_message: role == 'teacher_defined_test' ? feedback_message_nodes.first.content : nil,
file_type: FileType.find_by( file_type: FileType.find_by(
file_extension: ".#{file_name_split.second}" file_extension: ".#{file_name_split.second}"
@ -527,7 +527,7 @@ class Exercise < ApplicationRecord
if user if user
# FIXME: where(user: user) will not work here! # FIXME: where(user: user) will not work here!
begin begin
submissions.where(user: user).where("cause IN ('submit','assess')").where.not(score: nil).order('score DESC').first.score || 0 submissions.where(user:).where("cause IN ('submit','assess')").where.not(score: nil).order('score DESC').first.score || 0
rescue StandardError rescue StandardError
0 0
end end

View File

@ -14,7 +14,7 @@ class ExerciseTip < ApplicationRecord
def tip_chain? def tip_chain?
# Ensure each referenced parent exercise tip is set for this exercise # Ensure each referenced parent exercise tip is set for this exercise
unless ExerciseTip.exists?( unless ExerciseTip.exists?(
exercise: exercise, id: parent_exercise_tip exercise:, id: parent_exercise_tip
) )
errors.add :parent_exercise_tip, errors.add :parent_exercise_tip,
I18n.t('activerecord.errors.messages.together', I18n.t('activerecord.errors.messages.together',

View File

@ -10,7 +10,7 @@ class Intervention < ApplicationRecord
def self.create_default_interventions def self.create_default_interventions
%w[BreakIntervention QuestionIntervention].each do |name| %w[BreakIntervention QuestionIntervention].each do |name|
Intervention.find_or_create_by(name: name) Intervention.find_or_create_by(name:)
end end
end end
end end

View File

@ -19,12 +19,12 @@ class LinterCheckRun < ApplicationRecord
result: linter_result[:result], result: linter_result[:result],
line: linter_result[:line], line: linter_result[:line],
scope: linter_result[:scope], scope: linter_result[:scope],
testrun: testrun, testrun:,
file: file file:
) )
rescue ActiveRecord::RecordInvalid rescue ActiveRecord::RecordInvalid
# Something bad happened. Probably, the RegEx in lib/py_lint_adapter.rb didn't work. # Something bad happened. Probably, the RegEx in lib/py_lint_adapter.rb didn't work.
Sentry.set_extras(testrun: testrun.inspect, linter_result: linter_result) Sentry.set_extras(testrun: testrun.inspect, linter_result:)
end end
end end
end end

View File

@ -42,7 +42,7 @@ class ProxyExercise < ApplicationRecord
end end
def get_matching_exercise(user) def get_matching_exercise(user)
assigned_user_proxy_exercise = user_proxy_exercise_exercises.find_by(user: user) assigned_user_proxy_exercise = user_proxy_exercise_exercises.find_by(user:)
if assigned_user_proxy_exercise if assigned_user_proxy_exercise
Rails.logger.debug { "retrieved assigned exercise for user #{user.id}: Exercise #{assigned_user_proxy_exercise.exercise}" } Rails.logger.debug { "retrieved assigned exercise for user #{user.id}: Exercise #{assigned_user_proxy_exercise.exercise}" }
assigned_user_proxy_exercise.exercise assigned_user_proxy_exercise.exercise
@ -57,7 +57,7 @@ class ProxyExercise < ApplicationRecord
@reason[:error] = "#{$ERROR_INFO}:\n\t#{e.backtrace.join("\n\t")}" @reason[:error] = "#{$ERROR_INFO}:\n\t#{e.backtrace.join("\n\t")}"
exercises.where('expected_difficulty > 1').sample # difficulty should be > 1 to prevent dummy exercise from being chosen. exercises.where('expected_difficulty > 1').sample # difficulty should be > 1 to prevent dummy exercise from being chosen.
end end
user.user_proxy_exercise_exercises << UserProxyExerciseExercise.create(user: user, user.user_proxy_exercise_exercises << UserProxyExerciseExercise.create(user:,
exercise: matching_exercise, proxy_exercise: self, reason: @reason.to_json) exercise: matching_exercise, proxy_exercise: self, reason: @reason.to_json)
matching_exercise matching_exercise
end end
@ -105,9 +105,9 @@ class ProxyExercise < ApplicationRecord
relative_knowledge_improvement[potex] = 0.0 relative_knowledge_improvement[potex] = 0.0
Rails.logger.debug { "review potential exercise #{potex.id}" } Rails.logger.debug { "review potential exercise #{potex.id}" }
tags.each do |tag| tags.each do |tag|
tag_ratio = potex.exercise_tags.find_by(tag: tag).factor.to_f / potex.exercise_tags.inject(0) do |sum, et| tag_ratio = potex.exercise_tags.find_by(tag:).factor.to_f / potex.exercise_tags.inject(0) do |sum, et|
sum + et.factor sum + et.factor
end end
max_topic_knowledge_ratio = potex.expected_difficulty * tag_ratio max_topic_knowledge_ratio = potex.expected_difficulty * tag_ratio
old_relative_loss_tag = topic_knowledge_user[tag] / topic_knowledge_max[tag] old_relative_loss_tag = topic_knowledge_user[tag] / topic_knowledge_max[tag]
new_relative_loss_tag = topic_knowledge_user[tag] / (topic_knowledge_max[tag] + max_topic_knowledge_ratio) new_relative_loss_tag = topic_knowledge_user[tag] / (topic_knowledge_max[tag] + max_topic_knowledge_ratio)

View File

@ -31,9 +31,9 @@ class Runner < ApplicationRecord
end end
def self.for(user, execution_environment) def self.for(user, execution_environment)
runner = find_by(user: user, execution_environment: execution_environment) runner = find_by(user:, execution_environment:)
if runner.nil? if runner.nil?
runner = Runner.create(user: user, execution_environment: execution_environment) runner = Runner.create(user:, execution_environment:)
# The `strategy` is added through the before_validation hook `:request_id`. # The `strategy` is added through the before_validation hook `:request_id`.
raise Runner::Error::Unknown.new("Runner could not be saved: #{runner.errors.inspect}") unless runner.persisted? raise Runner::Error::Unknown.new("Runner could not be saved: #{runner.errors.inspect}") unless runner.persisted?
else else
@ -52,8 +52,8 @@ class Runner < ApplicationRecord
@strategy.copy_files(files) @strategy.copy_files(files)
end end
def download_file(path, **options, &block) def download_file(path, **options, &)
@strategy.download_file(path, **options, &block) @strategy.download_file(path, **options, &)
end end
def retrieve_files(raise_exception: true, **options) def retrieve_files(raise_exception: true, **options)
@ -93,7 +93,7 @@ class Runner < ApplicationRecord
# initializing its Runner::Connection with the given event loop. The Runner::Connection class ensures that # initializing its Runner::Connection with the given event loop. The Runner::Connection class ensures that
# this event loop is stopped after the socket was closed. # this event loop is stopped after the socket was closed.
event_loop = Runner::EventLoop.new event_loop = Runner::EventLoop.new
socket = @strategy.attach_to_execution(command, event_loop, starting_time, privileged_execution: privileged_execution, &block) socket = @strategy.attach_to_execution(command, event_loop, starting_time, privileged_execution:, &block)
event_loop.wait event_loop.wait
raise socket.error if socket.error.present? raise socket.error if socket.error.present?
rescue Runner::Error => e rescue Runner::Error => e
@ -120,7 +120,7 @@ class Runner < ApplicationRecord
save save
end end
execution_time = attach_to_execution(command, privileged_execution: privileged_execution) do |socket, starting_time| execution_time = attach_to_execution(command, privileged_execution:) do |socket, starting_time|
socket.on :stderr do |data| socket.on :stderr do |data|
output[:stderr] << data output[:stderr] << data
output[:messages].push({cmd: :write, stream: :stderr, log: data, timestamp: Time.zone.now - starting_time}) output[:messages].push({cmd: :write, stream: :stderr, log: data, timestamp: Time.zone.now - starting_time})

View File

@ -7,7 +7,7 @@ class StructuredError < ApplicationRecord
has_many :structured_error_attributes has_many :structured_error_attributes
def self.create_from_template(template, message_buffer, submission) def self.create_from_template(template, message_buffer, submission)
instance = create(error_template: template, submission: submission) instance = create(error_template: template, submission:)
template.error_template_attributes.each do |attribute| template.error_template_attributes.each do |attribute|
StructuredErrorAttribute.create_from_template(attribute, instance, message_buffer) StructuredErrorAttribute.create_from_template(attribute, instance, message_buffer)
end end

View File

@ -10,7 +10,7 @@ class StructuredErrorAttribute < ApplicationRecord
if !result.nil? && result.captures.size.positive? if !result.nil? && result.captures.size.positive?
value = result.captures[0] value = result.captures[0]
end end
create(structured_error: structured_error, error_template_attribute: attribute, value: value, create(structured_error:, error_template_attribute: attribute, value:,
match: !result.nil?) match: !result.nil?)
end end
end end

View File

@ -88,7 +88,7 @@ class Submission < ApplicationRecord
end end
def siblings def siblings
user.submissions.where(exercise_id: exercise_id) user.submissions.where(exercise_id:)
end end
def to_s def to_s
@ -129,7 +129,7 @@ class Submission < ApplicationRecord
end end
def own_unsolved_rfc def own_unsolved_rfc
RequestForComment.unsolved.find_by(exercise_id: exercise, user_id: user_id) RequestForComment.unsolved.find_by(exercise_id: exercise, user_id:)
end end
def unsolved_rfc def unsolved_rfc
@ -162,11 +162,11 @@ class Submission < ApplicationRecord
# @raise [Runner::Error] if the code could not be run due to a failure with the runner. # @raise [Runner::Error] if the code could not be run due to a failure with the runner.
# See the specific type and message for more details. # See the specific type and message for more details.
def run(file, &block) def run(file, &)
run_command = command_for execution_environment.run_command, file.filepath run_command = command_for execution_environment.run_command, file.filepath
durations = {} durations = {}
prepared_runner do |runner, waiting_duration| prepared_runner do |runner, waiting_duration|
durations[:execution_duration] = runner.attach_to_execution(run_command, &block) durations[:execution_duration] = runner.attach_to_execution(run_command, &)
durations[:waiting_duration] = waiting_duration durations[:waiting_duration] = waiting_duration
rescue Runner::Error => e rescue Runner::Error => e
e.waiting_duration = waiting_duration e.waiting_duration = waiting_duration
@ -237,13 +237,13 @@ class Submission < ApplicationRecord
def command_substitutions(filename) def command_substitutions(filename)
{ {
class_name: File.basename(filename, File.extname(filename)).upcase_first, class_name: File.basename(filename, File.extname(filename)).upcase_first,
filename: filename, filename:,
module_name: File.basename(filename, File.extname(filename)).underscore, module_name: File.basename(filename, File.extname(filename)).underscore,
} }
end end
def score_file(output, file) def score_file(output, file)
assessor = Assessor.new(execution_environment: execution_environment) assessor = Assessor.new(execution_environment:)
assessment = assessor.assess(output) assessment = assessor.assess(output)
passed = ((assessment[:passed] == assessment[:count]) and (assessment[:score]).positive?) passed = ((assessment[:passed] == assessment[:count]) and (assessment[:score]).positive?)
testrun_output = passed ? nil : "status: #{output[:status]}\n stdout: #{output[:stdout]}\n stderr: #{output[:stderr]}" testrun_output = passed ? nil : "status: #{output[:status]}\n stdout: #{output[:stdout]}\n stderr: #{output[:stderr]}"
@ -256,8 +256,8 @@ class Submission < ApplicationRecord
testrun = Testrun.create( testrun = Testrun.create(
submission: self, submission: self,
cause: 'assess', # Required to differ run and assess for RfC show cause: 'assess', # Required to differ run and assess for RfC show
file: file, # Test file that was executed file:, # Test file that was executed
passed: passed, passed:,
exit_code: output[:exit_code], exit_code: output[:exit_code],
status: output[:status], status: output[:status],
output: testrun_output.presence, output: testrun_output.presence,
@ -265,7 +265,7 @@ class Submission < ApplicationRecord
waiting_for_container_time: output[:waiting_for_container_time] waiting_for_container_time: output[:waiting_for_container_time]
) )
TestrunMessage.create_for(testrun, output[:messages]) TestrunMessage.create_for(testrun, output[:messages])
TestrunExecutionEnvironment.create(testrun: testrun, execution_environment: @used_execution_environment) TestrunExecutionEnvironment.create(testrun:, execution_environment: @used_execution_environment)
filename = file.filepath filename = file.filepath
@ -278,7 +278,7 @@ class Submission < ApplicationRecord
end end
output.merge!(assessment) output.merge!(assessment)
output.merge!(filename: filename, message: feedback_message(file, output), weight: file.weight) output.merge!(filename:, message: feedback_message(file, output), weight: file.weight)
output.except!(:messages) output.except!(:messages)
end end
@ -308,7 +308,7 @@ class Submission < ApplicationRecord
update(score: score.to_d) update(score: score.to_d)
if normalized_score.to_d == BigDecimal('1.0') if normalized_score.to_d == BigDecimal('1.0')
Thread.new do Thread.new do
RequestForComment.where(exercise_id: exercise_id, user_id: user_id, user_type: user_type).find_each do |rfc| RequestForComment.where(exercise_id:, user_id:, user_type:).find_each do |rfc|
rfc.full_score_reached = true rfc.full_score_reached = true
rfc.save rfc.save
end end

View File

@ -73,7 +73,7 @@ class User < ApplicationRecord
def to_sentry_context def to_sentry_context
{ {
id: id, id:,
type: self.class.name, type: self.class.name,
username: displayname, username: displayname,
consumer: consumer.name, consumer: consumer.name,

View File

@ -17,7 +17,7 @@ class UserExerciseFeedback < ApplicationRecord
end end
def anomaly_notification def anomaly_notification
AnomalyNotification.where({exercise_id: exercise.id, user_id: user_id, user_type: user_type}) AnomalyNotification.where({exercise_id: exercise.id, user_id:, user_type:})
.where('created_at < ?', created_at).order('created_at DESC').to_a.first .where('created_at < ?', created_at).order('created_at DESC').to_a.first
end end
end end

View File

@ -23,12 +23,12 @@ module ProformaService
title: @exercise.title, title: @exercise.title,
description: @exercise.description, description: @exercise.description,
internal_description: nil, internal_description: nil,
proglang: proglang, proglang:,
files: task_files, files: task_files,
tests: tests, tests:,
uuid: uuid, uuid:,
language: DEFAULT_LANGUAGE, language: DEFAULT_LANGUAGE,
model_solutions: model_solutions, model_solutions:,
meta_data: { meta_data: {
CodeOcean: { CodeOcean: {
public: @exercise.public, public: @exercise.public,

View File

@ -26,9 +26,9 @@ module ProformaService
allow_file_creation: string_to_bool(@task.meta_data[:CodeOcean]&.dig(:allow_file_creation)) || false, allow_file_creation: string_to_bool(@task.meta_data[:CodeOcean]&.dig(:allow_file_creation)) || false,
allow_auto_completion: string_to_bool(@task.meta_data[:CodeOcean]&.dig(:allow_auto_completion)) || false, allow_auto_completion: string_to_bool(@task.meta_data[:CodeOcean]&.dig(:allow_auto_completion)) || false,
expected_difficulty: @task.meta_data[:CodeOcean]&.dig(:expected_difficulty) || 1, expected_difficulty: @task.meta_data[:CodeOcean]&.dig(:expected_difficulty) || 1,
execution_environment_id: execution_environment_id, execution_environment_id:,
files: files files:
) )
end end

View File

@ -17,7 +17,7 @@ module ProformaService
exercise = base_exercise exercise = base_exercise
exercise_files = exercise&.files&.to_a exercise_files = exercise&.files&.to_a
exercise = ConvertTaskToExercise.call(task: @task, user: @user, exercise: exercise) exercise = ConvertTaskToExercise.call(task: @task, user: @user, exercise:)
exercise_files&.each(&:destroy) # feels suboptimal exercise_files&.each(&:destroy) # feels suboptimal
exercise exercise

View File

@ -8,7 +8,7 @@ json.download_file_url download_file_submission_path(@submission, 'a.', format:
unless @embed_options[:disable_download] unless @embed_options[:disable_download]
json.render_url @submission.collect_files.select(&:visible) do |files| json.render_url @submission.collect_files.select(&:visible) do |files|
host = ApplicationController::RENDER_HOST || request.host host = ApplicationController::RENDER_HOST || request.host
url = render_submission_url(@submission, files.filepath, host: host) url = render_submission_url(@submission, files.filepath, host:)
json.filepath files.filepath json.filepath files.filepath
json.url AuthenticatedUrlHelper.sign(url, @submission) json.url AuthenticatedUrlHelper.sign(url, @submission)

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
FILENAME_REGEXP = /.+/.freeze unless Kernel.const_defined?(:FILENAME_REGEXP) FILENAME_REGEXP = /.+/ unless Kernel.const_defined?(:FILENAME_REGEXP)
Rails.application.routes.draw do Rails.application.routes.draw do
resources :community_solutions, only: %i[index edit update] resources :community_solutions, only: %i[index edit update]

View File

@ -293,7 +293,7 @@ class MigrateTestruns < ActiveRecord::Migration[6.1]
# Using the string keys by design. Otherwise, we would need to call #symbolize_keys! # Using the string keys by design. Otherwise, we would need to call #symbolize_keys!
message = { message = {
testrun: testrun, testrun:,
cmd: json['cmd'], cmd: json['cmd'],
# We cannot infer any timestamp and thus use arbitrary, distinct millisecond values (1s = 1000ms) # We cannot infer any timestamp and thus use arbitrary, distinct millisecond values (1s = 1000ms)
timestamp: ActiveSupport::Duration.build(order / 1000.0), timestamp: ActiveSupport::Duration.build(order / 1000.0),

View File

@ -10,7 +10,7 @@ class MigratePermissionsToStudyGroup < ActiveRecord::Migration[6.1]
def create_default_groups def create_default_groups
Consumer.find_each do |consumer| Consumer.find_each do |consumer|
StudyGroup.find_or_create_by!(consumer: consumer, external_id: nil) do |new_group| StudyGroup.find_or_create_by!(consumer:, external_id: nil) do |new_group|
new_group.name = "Default Study Group for #{consumer.name}" new_group.name = "Default Study Group for #{consumer.name}"
end end
end end
@ -25,7 +25,7 @@ class MigratePermissionsToStudyGroup < ActiveRecord::Migration[6.1]
# All platform admins will "just" be a teacher in the study group # All platform admins will "just" be a teacher in the study group
new_role = %w[admin teacher].include?(user.role) ? :teacher : :learner new_role = %w[admin teacher].include?(user.role) ? :teacher : :learner
membership = StudyGroupMembership.find_or_create_by!(study_group: study_group, user: user) membership = StudyGroupMembership.find_or_create_by!(study_group:, user:)
membership.update_columns(role: new_role) membership.update_columns(role: new_role)
end end
end end

View File

@ -13,7 +13,7 @@ passwords = ['password', 'password confirmation'].map do |attribute|
end end
if passwords.uniq.length == 1 if passwords.uniq.length == 1
admin = FactoryBot.create(:admin, email: email, name: 'Administrator', password: passwords.first, study_groups: StudyGroup.all) admin = FactoryBot.create(:admin, email:, name: 'Administrator', password: passwords.first, study_groups: StudyGroup.all)
else else
abort('Passwords do not match!') abort('Passwords do not match!')
end end

View File

@ -1,10 +1,10 @@
# frozen_string_literal: true # frozen_string_literal: true
class CppCatch2Adapter < TestingFrameworkAdapter class CppCatch2Adapter < TestingFrameworkAdapter
ALL_PASSED_REGEXP = /in\s+(\d+)\s+test case/.freeze ALL_PASSED_REGEXP = /in\s+(\d+)\s+test case/
COUNT_REGEXP = /test cases:\s+(\d+)/.freeze COUNT_REGEXP = /test cases:\s+(\d+)/
FAILURES_REGEXP = / \|\s+(\d+)\s+failed/.freeze FAILURES_REGEXP = / \|\s+(\d+)\s+failed/
ASSERTION_ERROR_REGEXP = /\n(.+)error:(.+);/.freeze ASSERTION_ERROR_REGEXP = /\n(.+)error:(.+);/
def self.framework_name def self.framework_name
'CppCatch2' 'CppCatch2'
@ -17,7 +17,7 @@ class CppCatch2Adapter < TestingFrameworkAdapter
count = output[:stdout].scan(COUNT_REGEXP).try(:last).try(:first).try(:to_i) || 0 count = output[:stdout].scan(COUNT_REGEXP).try(:last).try(:first).try(:to_i) || 0
failed = output[:stdout].scan(FAILURES_REGEXP).try(:last).try(:first).try(:to_i) || 0 failed = output[:stdout].scan(FAILURES_REGEXP).try(:last).try(:first).try(:to_i) || 0
error_matches = output[:stdout].scan(ASSERTION_ERROR_REGEXP) || [] error_matches = output[:stdout].scan(ASSERTION_ERROR_REGEXP) || []
{count: count, failed: failed, error_messages: error_matches.flatten.compact_blank} {count:, failed:, error_messages: error_matches.flatten.compact_blank}
end end
end end
end end

View File

@ -1,9 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
class Junit5Adapter < TestingFrameworkAdapter class Junit5Adapter < TestingFrameworkAdapter
COUNT_REGEXP = /(\d+) tests found/.freeze COUNT_REGEXP = /(\d+) tests found/
FAILURES_REGEXP = /(\d+) tests failed/.freeze FAILURES_REGEXP = /(\d+) tests failed/
ASSERTION_ERROR_REGEXP = /=> java\.lang\.AssertionError:?\s(.*?)\s*org\.junit|=> org\.junit\.ComparisonFailure:\s(.*?)\s*org\.junit|=>\s(.*?)\s*org\.junit\.internal\.ComparisonCriteria\.arrayEquals|=> org\.opentest4j\.AssertionFailedError:?\s(.*?)\s*org.junit/m.freeze ASSERTION_ERROR_REGEXP = /=> java\.lang\.AssertionError:?\s(.*?)\s*org\.junit|=> org\.junit\.ComparisonFailure:\s(.*?)\s*org\.junit|=>\s(.*?)\s*org\.junit\.internal\.ComparisonCriteria\.arrayEquals|=> org\.opentest4j\.AssertionFailedError:?\s(.*?)\s*org.junit/m
def self.framework_name def self.framework_name
'JUnit 5' 'JUnit 5'
@ -13,10 +13,10 @@ class Junit5Adapter < TestingFrameworkAdapter
count = output[:stdout].scan(COUNT_REGEXP).try(:last).try(:first).try(:to_i) || 0 count = output[:stdout].scan(COUNT_REGEXP).try(:last).try(:first).try(:to_i) || 0
failed = output[:stdout].scan(FAILURES_REGEXP).try(:last).try(:first).try(:to_i) || 0 failed = output[:stdout].scan(FAILURES_REGEXP).try(:last).try(:first).try(:to_i) || 0
if failed.zero? if failed.zero?
{count: count, passed: count} {count:, passed: count}
else else
error_matches = output[:stdout].scan(ASSERTION_ERROR_REGEXP) || [] error_matches = output[:stdout].scan(ASSERTION_ERROR_REGEXP) || []
{count: count, failed: failed, error_messages: error_matches.flatten.compact_blank} {count:, failed:, error_messages: error_matches.flatten.compact_blank}
end end
end end
end end

View File

@ -1,10 +1,10 @@
# frozen_string_literal: true # frozen_string_literal: true
class JunitAdapter < TestingFrameworkAdapter class JunitAdapter < TestingFrameworkAdapter
COUNT_REGEXP = /Tests run: (\d+)/.freeze COUNT_REGEXP = /Tests run: (\d+)/
FAILURES_REGEXP = /Failures: (\d+)/.freeze FAILURES_REGEXP = /Failures: (\d+)/
SUCCESS_REGEXP = /OK \((\d+) tests?\)\s*(?:\x1B\]0;|exit)?\s*\z/.freeze SUCCESS_REGEXP = /OK \((\d+) tests?\)\s*(?:\x1B\]0;|exit)?\s*\z/
ASSERTION_ERROR_REGEXP = /java\.lang\.AssertionError:?\s(.*?)\tat org\.junit|org\.junit\.ComparisonFailure:\s(.*?)\tat org\.junit|\)\r\n(.*?)\tat org\.junit\.internal\.ComparisonCriteria\.arrayEquals\(ComparisonCriteria\.java:50\)/m.freeze ASSERTION_ERROR_REGEXP = /java\.lang\.AssertionError:?\s(.*?)\tat org\.junit|org\.junit\.ComparisonFailure:\s(.*?)\tat org\.junit|\)\r\n(.*?)\tat org\.junit\.internal\.ComparisonCriteria\.arrayEquals\(ComparisonCriteria\.java:50\)/m
def self.framework_name def self.framework_name
'JUnit 4' 'JUnit 4'
@ -17,7 +17,7 @@ class JunitAdapter < TestingFrameworkAdapter
count = output[:stdout].scan(COUNT_REGEXP).try(:last).try(:first).try(:to_i) || 0 count = output[:stdout].scan(COUNT_REGEXP).try(:last).try(:first).try(:to_i) || 0
failed = output[:stdout].scan(FAILURES_REGEXP).try(:last).try(:first).try(:to_i) || 0 failed = output[:stdout].scan(FAILURES_REGEXP).try(:last).try(:first).try(:to_i) || 0
error_matches = output[:stdout].scan(ASSERTION_ERROR_REGEXP) || [] error_matches = output[:stdout].scan(ASSERTION_ERROR_REGEXP) || []
{count: count, failed: failed, error_messages: error_matches.flatten.compact_blank} {count:, failed:, error_messages: error_matches.flatten.compact_blank}
end end
end end
end end

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
class MochaAdapter < TestingFrameworkAdapter class MochaAdapter < TestingFrameworkAdapter
SUCCESS_REGEXP = /(\d+) passing/.freeze SUCCESS_REGEXP = /(\d+) passing/
FAILURES_REGEXP = /(\d+) failing/.freeze FAILURES_REGEXP = /(\d+) failing/
def self.framework_name def self.framework_name
'Mocha' 'Mocha'
@ -11,6 +11,6 @@ class MochaAdapter < TestingFrameworkAdapter
def parse_output(output) def parse_output(output)
success = output[:stdout].scan(SUCCESS_REGEXP).try(:last).try(:first).try(:to_i) || 0 success = output[:stdout].scan(SUCCESS_REGEXP).try(:last).try(:first).try(:to_i) || 0
failed = output[:stdout].scan(FAILURES_REGEXP).try(:last).try(:first).try(:to_i) || 0 failed = output[:stdout].scan(FAILURES_REGEXP).try(:last).try(:first).try(:to_i) || 0
{count: success + failed, failed: failed} {count: success + failed, failed:}
end end
end end

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
class PyLintAdapter < TestingFrameworkAdapter class PyLintAdapter < TestingFrameworkAdapter
REGEXP = %r{Your code has been rated at (-?\d+\.?\d*)/(\d+\.?\d*)}.freeze REGEXP = %r{Your code has been rated at (-?\d+\.?\d*)/(\d+\.?\d*)}
ASSERTION_ERROR_REGEXP = /^(.*?\.py):(\d+):(.*?)\(([^,]*?), ([^,]*?),([^,]*?)\) (.*?)$/.freeze ASSERTION_ERROR_REGEXP = /^(.*?\.py):(\d+):(.*?)\(([^,]*?), ([^,]*?),([^,]*?)\) (.*?)$/
def self.framework_name def self.framework_name
'PyLint' 'PyLint'
@ -41,8 +41,8 @@ class PyLintAdapter < TestingFrameworkAdapter
end end
concatenated_errors = assertion_error_matches.map {|result| "#{result[:name]}: #{result[:result]}" } concatenated_errors = assertion_error_matches.map {|result| "#{result[:name]}: #{result[:result]}" }
{ {
count: count, count:,
failed: failed, failed:,
error_messages: concatenated_errors.flatten.compact_blank, error_messages: concatenated_errors.flatten.compact_blank,
detailed_linter_results: assertion_error_matches.flatten.compact_blank, detailed_linter_results: assertion_error_matches.flatten.compact_blank,
} }
@ -69,7 +69,7 @@ class PyLintAdapter < TestingFrameworkAdapter
captures = message[:result].match(Regexp.new(regex))&.named_captures&.symbolize_keys captures = message[:result].match(Regexp.new(regex))&.named_captures&.symbolize_keys
if captures.nil? if captures.nil?
Sentry.capture_message({regex: regex, message: message[:result]}.to_json) Sentry.capture_message({regex:, message: message[:result]}.to_json)
replacement = {} replacement = {}
else else
replacement = captures.each do |key, value| replacement = captures.each do |key, value|
@ -100,7 +100,7 @@ class PyLintAdapter < TestingFrameworkAdapter
def self.get_t(key, default) def self.get_t(key, default)
# key might be "linter.#{severity}.#{name}.#{key}.#{value}" # key might be "linter.#{severity}.#{name}.#{key}.#{value}"
# or something like "linter.#{severity}.#{name}.replacement" # or something like "linter.#{severity}.#{name}.replacement"
translation = I18n.t(key, default: default) translation = I18n.t(key, default:)
cleaned_key = key.delete_suffix(".#{default}") # Remove any custom prefix, might have no effect cleaned_key = key.delete_suffix(".#{default}") # Remove any custom prefix, might have no effect
keys = cleaned_key.split('.') keys = cleaned_key.split('.')
final_key = keys.pop final_key = keys.pop
@ -111,7 +111,7 @@ class PyLintAdapter < TestingFrameworkAdapter
# Read config key # Read config key
I18n.t(keys.append('log_missing').join('.'), default: false) I18n.t(keys.append('log_missing').join('.'), default: false)
end end
Sentry.capture_message({key: cleaned_key, default: default}.to_json) if translation == default && log_missing Sentry.capture_message({key: cleaned_key, default:}.to_json) if translation == default && log_missing
translation translation
end end
end end

View File

@ -1,10 +1,10 @@
# frozen_string_literal: true # frozen_string_literal: true
class PyUnitAdapter < TestingFrameworkAdapter class PyUnitAdapter < TestingFrameworkAdapter
COUNT_REGEXP = /Ran (\d+) test/.freeze COUNT_REGEXP = /Ran (\d+) test/
FAILURES_REGEXP = /FAILED \(.*failures=(\d+).*\)/.freeze FAILURES_REGEXP = /FAILED \(.*failures=(\d+).*\)/
ERRORS_REGEXP = /FAILED \(.*errors=(\d+).*\)/.freeze ERRORS_REGEXP = /FAILED \(.*errors=(\d+).*\)/
ASSERTION_ERROR_REGEXP = /^(ERROR|FAIL):\ (.*?)\ .*?^[^.\n]*?(Error|Exception):\s((\s|\S)*?)(>>>[^>]*?)*\s\s(-|=){70}/m.freeze ASSERTION_ERROR_REGEXP = /^(ERROR|FAIL):\ (.*?)\ .*?^[^.\n]*?(Error|Exception):\s((\s|\S)*?)(>>>[^>]*?)*\s\s(-|=){70}/m
def self.framework_name def self.framework_name
'PyUnit' 'PyUnit'
@ -32,6 +32,6 @@ class PyUnitAdapter < TestingFrameworkAdapter
Sentry.capture_message({stderr: output[:stderr], regex: ASSERTION_ERROR_REGEXP}.to_json) Sentry.capture_message({stderr: output[:stderr], regex: ASSERTION_ERROR_REGEXP}.to_json)
assertion_error_matches = [] assertion_error_matches = []
end end
{count: count, failed: failed + errors, error_messages: assertion_error_matches.flatten.compact_blank} {count:, failed: failed + errors, error_messages: assertion_error_matches.flatten.compact_blank}
end end
end end

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
class RScriptAdapter < TestingFrameworkAdapter class RScriptAdapter < TestingFrameworkAdapter
REGEXP = /(\d+) examples?, (\d+) passed?/.freeze REGEXP = /(\d+) examples?, (\d+) passed?/
ASSERTION_ERROR_REGEXP = /AssertionError:\s(.*)/.freeze ASSERTION_ERROR_REGEXP = /AssertionError:\s(.*)/
def self.framework_name def self.framework_name
'R Script' 'R Script'
@ -14,6 +14,6 @@ class RScriptAdapter < TestingFrameworkAdapter
passed = captures.second passed = captures.second
failed = count - passed failed = count - passed
assertion_error_matches = output[:stdout].scan(ASSERTION_ERROR_REGEXP) || [] assertion_error_matches = output[:stdout].scan(ASSERTION_ERROR_REGEXP) || []
{count: count, failed: failed, error_messages: assertion_error_matches.flatten.compact_blank} {count:, failed:, error_messages: assertion_error_matches.flatten.compact_blank}
end end
end end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class RspecAdapter < TestingFrameworkAdapter class RspecAdapter < TestingFrameworkAdapter
REGEXP = /(\d+) examples?, (\d+) failures?/.freeze REGEXP = /(\d+) examples?, (\d+) failures?/
def self.framework_name def self.framework_name
'RSpec 3' 'RSpec 3'
@ -11,6 +11,6 @@ class RspecAdapter < TestingFrameworkAdapter
captures = output[:stdout].scan(REGEXP).try(:last).map(&:to_i) captures = output[:stdout].scan(REGEXP).try(:last).map(&:to_i)
count = captures.first count = captures.first
failed = captures.second failed = captures.second
{count: count, failed: failed} {count:, failed:}
end end
end end

View File

@ -128,7 +128,7 @@ class Runner::Strategy::Poseidon < Runner::Strategy
# First, clean the workspace and second, copy all files to their location. # First, clean the workspace and second, copy all files to their location.
# This ensures that no artifacts from a previous submission remain in the workspace. # This ensures that no artifacts from a previous submission remain in the workspace.
body = {copy: copy, delete: ['./*']} body = {copy:, delete: ['./*']}
response = self.class.http_connection.patch url, body.to_json response = self.class.http_connection.patch url, body.to_json
return if response.status == 204 return if response.status == 204
@ -143,8 +143,8 @@ class Runner::Strategy::Poseidon < Runner::Strategy
def retrieve_files(path: './', recursive: true, privileged_execution: false) def retrieve_files(path: './', recursive: true, privileged_execution: false)
url = "#{runner_url}/files" url = "#{runner_url}/files"
params = { params = {
path: path, path:,
recursive: recursive, recursive:,
privilegedExecution: privileged_execution || @execution_environment.privileged_execution, privilegedExecution: privileged_execution || @execution_environment.privileged_execution,
} }
Rails.logger.debug { "#{Time.zone.now.getutc.inspect}: Retrieving files at #{runner_url} with #{params}" } Rails.logger.debug { "#{Time.zone.now.getutc.inspect}: Retrieving files at #{runner_url} with #{params}" }
@ -199,7 +199,7 @@ class Runner::Strategy::Poseidon < Runner::Strategy
end end
def attach_to_execution(command, event_loop, starting_time, privileged_execution: false) def attach_to_execution(command, event_loop, starting_time, privileged_execution: false)
websocket_url = execute_command(command, privileged_execution: privileged_execution) websocket_url = execute_command(command, privileged_execution:)
socket = Connection.new(websocket_url, self, event_loop) socket = Connection.new(websocket_url, self, event_loop)
yield(socket, starting_time) yield(socket, starting_time)
socket socket
@ -293,13 +293,13 @@ class Runner::Strategy::Poseidon < Runner::Strategy
end end
def self.http_connection def self.http_connection
@http_connection ||= Faraday.new(ssl: {ca_file: config[:ca_file]}, headers: headers) do |faraday| @http_connection ||= Faraday.new(ssl: {ca_file: config[:ca_file]}, headers:) do |faraday|
faraday.adapter :net_http_persistent faraday.adapter :net_http_persistent
end end
end end
def self.new_http_connection def self.new_http_connection
Faraday.new(ssl: {ca_file: config[:ca_file]}, headers: headers) do |faraday| Faraday.new(ssl: {ca_file: config[:ca_file]}, headers:) do |faraday|
faraday.adapter :net_http faraday.adapter :net_http
end end
end end
@ -316,7 +316,7 @@ class Runner::Strategy::Poseidon < Runner::Strategy
def execute_command(command, privileged_execution: false) def execute_command(command, privileged_execution: false)
url = "#{runner_url}/execute" url = "#{runner_url}/execute"
body = { body = {
command: command, command:,
timeLimit: @execution_environment.permitted_execution_time, timeLimit: @execution_environment.permitted_execution_time,
privilegedExecution: privileged_execution || @execution_environment.privileged_execution, privilegedExecution: privileged_execution || @execution_environment.privileged_execution,
} }

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
class SqlResultSetComparatorAdapter < TestingFrameworkAdapter class SqlResultSetComparatorAdapter < TestingFrameworkAdapter
MISSING_TUPLES_REGEXP = /Missing tuples: \[\]/.freeze MISSING_TUPLES_REGEXP = /Missing tuples: \[\]/
UNEXPECTED_TUPLES_REGEXP = /Unexpected tuples: \[\]/.freeze UNEXPECTED_TUPLES_REGEXP = /Unexpected tuples: \[\]/
def self.framework_name def self.framework_name
'SqlResultSetComparator' 'SqlResultSetComparator'

View File

@ -133,7 +133,7 @@ namespace :detect_exercise_anomalies do
segment.each do |user| segment.each do |user|
reason = "{\"segment\": \"#{key}\", \"feature\": \"#{user[:reason]}\", value: \"#{user[:value]}\"}" reason = "{\"segment\": \"#{key}\", \"feature\": \"#{user[:reason]}\", value: \"#{user[:value]}\"}"
AnomalyNotification.create(user_id: user[:user_id], user_type: user[:user_type], AnomalyNotification.create(user_id: user[:user_id], user_type: user[:user_type],
exercise: exercise, exercise_collection: collection, reason: reason) exercise:, exercise_collection: collection, reason:)
end end
end end
@ -142,7 +142,7 @@ namespace :detect_exercise_anomalies do
user = u[:user_type] == InternalUser.name ? InternalUser.find(u[:user_id]) : ExternalUser.find(u[:user_id]) user = u[:user_type] == InternalUser.name ? InternalUser.find(u[:user_id]) : ExternalUser.find(u[:user_id])
host = CodeOcean::Application.config.action_mailer.default_url_options[:host] host = CodeOcean::Application.config.action_mailer.default_url_options[:host]
feedback_link = Rails.application.routes.url_helpers.url_for(action: :new, feedback_link = Rails.application.routes.url_helpers.url_for(action: :new,
controller: :user_exercise_feedbacks, exercise_id: exercise.id, host: host) controller: :user_exercise_feedbacks, exercise_id: exercise.id, host:)
UserMailer.exercise_anomaly_needs_feedback(user, exercise, feedback_link).deliver UserMailer.exercise_anomaly_needs_feedback(user, exercise, feedback_link).deliver
end end
log("Asked #{users_to_notify.size} users for feedback.", 2) log("Asked #{users_to_notify.size} users for feedback.", 2)

View File

@ -9,8 +9,8 @@ namespace :export_exercises do
Exercise.where(public: true).each do |exercise| Exercise.where(public: true).each do |exercise|
puts "Exporting exercise ##{exercise.id}" puts "Exporting exercise ##{exercise.id}"
error = ExerciseService::PushExternal.call( error = ExerciseService::PushExternal.call(
zip: ProformaService::ExportTask.call(exercise: exercise), zip: ProformaService::ExportTask.call(exercise:),
codeharbor_link: codeharbor_link codeharbor_link:
) )
if error.nil? if error.nil?
successful_exports << exercise.id successful_exports << exercise.id

View File

@ -56,7 +56,7 @@ describe Lti do
it 'returns to the tool consumer' do it 'returns to the tool consumer' do
message = I18n.t('sessions.oauth.invalid_consumer') message = I18n.t('sessions.oauth.invalid_consumer')
expect(controller).to receive(:return_to_consumer).with(lti_errorlog: message, lti_errormsg: I18n.t('sessions.oauth.failure')) expect(controller).to receive(:return_to_consumer).with(lti_errorlog: message, lti_errormsg: I18n.t('sessions.oauth.failure'))
controller.send(:refuse_lti_launch, message: message) controller.send(:refuse_lti_launch, message:)
end end
end end
@ -174,14 +174,14 @@ describe Lti do
controller.instance_variable_set(:@exercise, create(:fibonacci)) controller.instance_variable_set(:@exercise, create(:fibonacci))
expect(controller.session).to receive(:[]=).with(:external_user_id, anything) expect(controller.session).to receive(:[]=).with(:external_user_id, anything)
expect(controller.session).to receive(:[]=).with(:lti_parameters_id, anything) expect(controller.session).to receive(:[]=).with(:lti_parameters_id, anything)
controller.send(:store_lti_session_data, consumer: build(:consumer), parameters: parameters) controller.send(:store_lti_session_data, consumer: build(:consumer), parameters:)
end end
it 'creates an LtiParameter Object' do it 'creates an LtiParameter Object' do
before_count = LtiParameter.count before_count = LtiParameter.count
controller.instance_variable_set(:@current_user, create(:external_user)) controller.instance_variable_set(:@current_user, create(:external_user))
controller.instance_variable_set(:@exercise, create(:fibonacci)) controller.instance_variable_set(:@exercise, create(:fibonacci))
controller.send(:store_lti_session_data, consumer: build(:consumer), parameters: parameters) controller.send(:store_lti_session_data, consumer: build(:consumer), parameters:)
expect(LtiParameter.count).to eq(before_count + 1) expect(LtiParameter.count).to eq(before_count + 1)
end end
end end

View File

@ -76,7 +76,7 @@ describe ApplicationController do
context "when using the 'locale' parameter" do context "when using the 'locale' parameter" do
it 'overwrites the session' do it 'overwrites the session' do
expect(session).to receive(:[]=).with(:locale, locale) expect(session).to receive(:[]=).with(:locale, locale)
get :welcome, params: {locale: locale} get :welcome, params: {locale:}
end end
end end
end end

View File

@ -30,7 +30,7 @@ describe CodeOcean::FilesController do
end end
describe 'POST #create' do describe 'POST #create' do
let(:submission) { create(:submission, user: user) } let(:submission) { create(:submission, user:) }
context 'with a valid file' do context 'with a valid file' do
let(:perform_request) { proc { post :create, params: {code_ocean_file: build(:file, context: submission).attributes, format: :json} } } let(:perform_request) { proc { post :create, params: {code_ocean_file: build(:file, context: submission).attributes, format: :json} } }

View File

@ -22,7 +22,7 @@ describe CodeharborLinksController do
end end
describe 'GET #edit' do describe 'GET #edit' do
let(:codeharbor_link) { create(:codeharbor_link, user: user) } let(:codeharbor_link) { create(:codeharbor_link, user:) }
before { get :edit, params: {id: codeharbor_link.id} } before { get :edit, params: {id: codeharbor_link.id} }
@ -56,7 +56,7 @@ describe CodeharborLinksController do
end end
describe 'PUT #update' do describe 'PUT #update' do
let(:codeharbor_link) { create(:codeharbor_link, user: user) } let(:codeharbor_link) { create(:codeharbor_link, user:) }
let(:put_request) { patch :update, params: {id: codeharbor_link.id, codeharbor_link: params} } let(:put_request) { patch :update, params: {id: codeharbor_link.id, codeharbor_link: params} }
let(:params) { {push_url: 'https://foo.bar/push', check_uuid_url: 'https://foo.bar/check', api_key: 'api_key'} } let(:params) { {push_url: 'https://foo.bar/push', check_uuid_url: 'https://foo.bar/check', api_key: 'api_key'} }
@ -91,7 +91,7 @@ describe CodeharborLinksController do
end end
describe 'DELETE #destroy' do describe 'DELETE #destroy' do
let!(:codeharbor_link) { create(:codeharbor_link, user: user) } let!(:codeharbor_link) { create(:codeharbor_link, user:) }
let(:destroy_request) { delete :destroy, params: {id: codeharbor_link.id} } let(:destroy_request) { delete :destroy, params: {id: codeharbor_link.id} }
it 'deletes codeharbor_link' do it 'deletes codeharbor_link' do

View File

@ -6,7 +6,7 @@ describe CommentsController do
render_views render_views
let(:user) { create(:learner) } let(:user) { create(:learner) }
let(:rfc_with_comment) { create(:rfc_with_comment, user: user) } let(:rfc_with_comment) { create(:rfc_with_comment, user:) }
let(:comment) { rfc_with_comment.comments.first } let(:comment) { rfc_with_comment.comments.first }
let(:updated_comment) { comment.reload } let(:updated_comment) { comment.reload }
let(:perform_request) { proc { put :update, format: :json, params: {id: comment.id, comment: comment_params} } } let(:perform_request) { proc { put :update, format: :json, params: {id: comment.id, comment: comment_params} } }

View File

@ -95,7 +95,7 @@ describe ExecutionEnvironmentsController do
runner = instance_double Runner runner = instance_double Runner
allow(Runner).to receive(:for).with(user, execution_environment).and_return runner allow(Runner).to receive(:for).with(user, execution_environment).and_return runner
allow(runner).to receive(:execute_command).and_return({}) allow(runner).to receive(:execute_command).and_return({})
post :execute_command, params: {command: command, id: execution_environment.id} post :execute_command, params: {command:, id: execution_environment.id}
end end
expect_assigns(execution_environment: :execution_environment) expect_assigns(execution_environment: :execution_environment)

View File

@ -37,7 +37,7 @@ describe ExercisesController do
expect_assigns(exercise: Exercise) expect_assigns(exercise: Exercise)
it 'clones the exercise' do it 'clones the exercise' do
expect_any_instance_of(Exercise).to receive(:duplicate).with(hash_including(public: false, user: user)).and_call_original expect_any_instance_of(Exercise).to receive(:duplicate).with(hash_including(public: false, user:)).and_call_original
expect { perform_request.call }.to change(Exercise, :count).by(1) expect { perform_request.call }.to change(Exercise, :count).by(1)
end end
@ -78,7 +78,7 @@ describe ExercisesController do
end end
context 'when including a file' do context 'when including a file' do
let(:perform_request) { proc { post :create, params: {exercise: exercise_attributes.merge(files_attributes: files_attributes)} } } let(:perform_request) { proc { post :create, params: {exercise: exercise_attributes.merge(files_attributes:)} } }
context 'when specifying the file content within the form' do context 'when specifying the file content within the form' do
let(:files_attributes) { {'0' => build(:file).attributes} } let(:files_attributes) { {'0' => build(:file).attributes} }
@ -89,7 +89,7 @@ describe ExercisesController do
end end
context 'when uploading a file' do context 'when uploading a file' do
let(:files_attributes) { {'0' => build(:file, file_type: file_type).attributes.merge(content: uploaded_file)} } let(:files_attributes) { {'0' => build(:file, file_type:).attributes.merge(content: uploaded_file)} }
context 'when uploading a binary file' do context 'when uploading a binary file' do
let(:file_path) { Rails.root.join('db/seeds/audio_video/devstories.mp4') } let(:file_path) { Rails.root.join('db/seeds/audio_video/devstories.mp4') }
@ -255,14 +255,14 @@ describe ExercisesController do
end end
describe 'GET #external_user_statistics' do describe 'GET #external_user_statistics' do
let(:perform_request) { get :external_user_statistics, params: params } let(:perform_request) { get :external_user_statistics, params: }
let(:params) { {id: exercise.id, external_user_id: external_user.id} } let(:params) { {id: exercise.id, external_user_id: external_user.id} }
let(:external_user) { create(:external_user) } let(:external_user) { create(:external_user) }
before do before do
2.times { create(:submission, cause: 'autosave', user: external_user, exercise: exercise) } 2.times { create(:submission, cause: 'autosave', user: external_user, exercise:) }
2.times { create(:submission, cause: 'run', user: external_user, exercise: exercise) } 2.times { create(:submission, cause: 'run', user: external_user, exercise:) }
create(:submission, cause: 'assess', user: external_user, exercise: exercise) create(:submission, cause: 'assess', user: external_user, exercise:)
end end
context 'when viewing the default submission statistics page without a parameter' do context 'when viewing the default submission statistics page without a parameter' do
@ -312,8 +312,8 @@ describe ExercisesController do
end end
before do before do
create(:lti_parameter, external_user: user, exercise: exercise) create(:lti_parameter, external_user: user, exercise:)
submission = build(:submission, exercise: exercise, user: user) submission = build(:submission, exercise:, user:)
allow(submission).to receive(:normalized_score).and_return(1) allow(submission).to receive(:normalized_score).and_return(1)
allow(submission).to receive(:calculate_score).and_return(scoring_response) allow(submission).to receive(:calculate_score).and_return(scoring_response)
allow(Submission).to receive(:create).and_return(submission) allow(Submission).to receive(:create).and_return(submission)
@ -404,13 +404,13 @@ describe ExercisesController do
render_views render_views
let(:post_request) { post :export_external_check, params: {id: exercise.id} } let(:post_request) { post :export_external_check, params: {id: exercise.id} }
let!(:codeharbor_link) { create(:codeharbor_link, user: user) } let!(:codeharbor_link) { create(:codeharbor_link, user:) }
let(:external_check_hash) { {message: message, uuid_found: true, update_right: update_right, error: error} } let(:external_check_hash) { {message:, uuid_found: true, update_right:, error:} }
let(:message) { 'message' } let(:message) { 'message' }
let(:update_right) { true } let(:update_right) { true }
let(:error) { nil } let(:error) { nil }
before { allow(ExerciseService::CheckExternal).to receive(:call).with(uuid: exercise.uuid, codeharbor_link: codeharbor_link).and_return(external_check_hash) } before { allow(ExerciseService::CheckExternal).to receive(:call).with(uuid: exercise.uuid, codeharbor_link:).and_return(external_check_hash) }
it 'renders the correct contents as json' do it 'renders the correct contents as json' do
post_request post_request
@ -457,14 +457,14 @@ describe ExercisesController do
describe 'POST #export_external_confirm' do describe 'POST #export_external_confirm' do
render_views render_views
let!(:codeharbor_link) { create(:codeharbor_link, user: user) } let!(:codeharbor_link) { create(:codeharbor_link, user:) }
let(:post_request) { post :export_external_confirm, params: {id: exercise.id, codeharbor_link: codeharbor_link.id} } let(:post_request) { post :export_external_confirm, params: {id: exercise.id, codeharbor_link: codeharbor_link.id} }
let(:error) { nil } let(:error) { nil }
let(:zip) { 'zip' } let(:zip) { 'zip' }
before do before do
allow(ProformaService::ExportTask).to receive(:call).with(exercise: exercise).and_return(zip) allow(ProformaService::ExportTask).to receive(:call).with(exercise:).and_return(zip)
allow(ExerciseService::PushExternal).to receive(:call).with(zip: zip, codeharbor_link: codeharbor_link).and_return(error) allow(ExerciseService::PushExternal).to receive(:call).with(zip:, codeharbor_link:).and_return(error)
end end
it 'renders correct response' do it 'renders correct response' do
@ -493,9 +493,9 @@ describe ExercisesController do
describe 'POST #import_uuid_check' do describe 'POST #import_uuid_check' do
let(:exercise) { create(:dummy, uuid: SecureRandom.uuid) } let(:exercise) { create(:dummy, uuid: SecureRandom.uuid) }
let!(:codeharbor_link) { create(:codeharbor_link, user: user) } let!(:codeharbor_link) { create(:codeharbor_link, user:) }
let(:uuid) { exercise.reload.uuid } let(:uuid) { exercise.reload.uuid }
let(:post_request) { post :import_uuid_check, params: {uuid: uuid} } let(:post_request) { post :import_uuid_check, params: {uuid:} }
let(:headers) { {'Authorization' => "Bearer #{codeharbor_link.api_key}"} } let(:headers) { {'Authorization' => "Bearer #{codeharbor_link.api_key}"} }
before { request.headers.merge! headers } before { request.headers.merge! headers }
@ -542,7 +542,7 @@ describe ExercisesController do
end end
describe 'POST #import_task' do describe 'POST #import_task' do
let(:codeharbor_link) { create(:codeharbor_link, user: user) } let(:codeharbor_link) { create(:codeharbor_link, user:) }
let!(:imported_exercise) { create(:fibonacci) } let!(:imported_exercise) { create(:fibonacci) }
let(:post_request) { post :import_task, body: zip_file_content } let(:post_request) { post :import_task, body: zip_file_content }
let(:zip_file_content) { 'zipped task xml' } let(:zip_file_content) { 'zipped task xml' }
@ -560,7 +560,7 @@ describe ExercisesController do
it 'calls service' do it 'calls service' do
post_request post_request
expect(ProformaService::Import).to have_received(:call).with(zip: be_a(Tempfile).and(has_content(zip_file_content)), user: user) expect(ProformaService::Import).to have_received(:call).with(zip: be_a(Tempfile).and(has_content(zip_file_content)), user:)
end end
context 'when import fails with ProformaError' do context 'when import fails with ProformaError' do

View File

@ -61,7 +61,7 @@ describe InternalUsersController do
context 'with an already activated user' do context 'with an already activated user' do
before do before do
user.activate! user.activate!
put :activate, params: {id: user.id, internal_user: {activation_token: user.activation_token, password: password, password_confirmation: password}} put :activate, params: {id: user.id, internal_user: {activation_token: user.activation_token, password:, password_confirmation: password}}
end end
expect_redirect(:root) expect_redirect(:root)
@ -80,7 +80,7 @@ describe InternalUsersController do
end end
context 'without a valid password confirmation' do context 'without a valid password confirmation' do
before { put :activate, params: {id: user.id, internal_user: {activation_token: user.activation_token, password: password, password_confirmation: ''}} } before { put :activate, params: {id: user.id, internal_user: {activation_token: user.activation_token, password:, password_confirmation: ''}} }
expect_assigns(user: InternalUser) expect_assigns(user: InternalUser)
@ -92,7 +92,7 @@ describe InternalUsersController do
end end
context 'with valid preconditions' do context 'with valid preconditions' do
before { put :activate, params: {id: user.id, internal_user: {activation_token: user.activation_token, password: password, password_confirmation: password}} } before { put :activate, params: {id: user.id, internal_user: {activation_token: user.activation_token, password:, password_confirmation: password}} }
expect_assigns(user: InternalUser) expect_assigns(user: InternalUser)
@ -278,7 +278,7 @@ describe InternalUsersController do
let(:password) { 'foo' } let(:password) { 'foo' }
context 'with a matching password confirmation' do context 'with a matching password confirmation' do
let(:perform_request) { proc { put :reset_password, params: {internal_user: {password: password, password_confirmation: password}, id: user.id, token: user.reset_password_token} } } let(:perform_request) { proc { put :reset_password, params: {internal_user: {password:, password_confirmation: password}, id: user.id, token: user.reset_password_token} } }
before { perform_request.call } before { perform_request.call }
@ -310,7 +310,7 @@ describe InternalUsersController do
context 'without a matching password confirmation' do context 'without a matching password confirmation' do
before do before do
put :reset_password, params: {internal_user: {password: password, password_confirmation: ''}, id: user.id, token: user.reset_password_token} put :reset_password, params: {internal_user: {password:, password_confirmation: ''}, id: user.id, token: user.reset_password_token}
end end
expect_assigns(user: :user) expect_assigns(user: :user)

View File

@ -19,7 +19,7 @@ describe RequestForCommentsController do
it 'shows only rfc`s belonging to selected study group' do it 'shows only rfc`s belonging to selected study group' do
my_study_group = create(:study_group) my_study_group = create(:study_group)
rfc_within_my_study_group = create(:rfc, user: user) rfc_within_my_study_group = create(:rfc, user:)
user.update(study_groups: [my_study_group]) user.update(study_groups: [my_study_group])
rfc_within_my_study_group.submission.update(study_group: my_study_group) rfc_within_my_study_group.submission.update(study_group: my_study_group)

View File

@ -9,13 +9,13 @@ describe SessionsController do
describe 'POST #create' do describe 'POST #create' do
let(:password) { attributes_for(:teacher)[:password] } let(:password) { attributes_for(:teacher)[:password] }
let(:user) { InternalUser.create(user_attributes.merge(password: password)) } let(:user) { InternalUser.create(user_attributes.merge(password:)) }
let(:user_attributes) { build(:teacher).attributes } let(:user_attributes) { build(:teacher).attributes }
context 'with valid credentials' do context 'with valid credentials' do
before do before do
user.activate! user.activate!
post :create, params: {email: user.email, password: password, remember_me: 1} post :create, params: {email: user.email, password:, remember_me: 1}
end end
expect_flash_message(:notice, :'sessions.create.success') expect_flash_message(:notice, :'sessions.create.success')
@ -113,7 +113,7 @@ describe SessionsController do
context 'when LTI outcomes are supported' do context 'when LTI outcomes are supported' do
# The expected message should be localized in the requested localization # The expected message should be localized in the requested localization
let(:message) { I18n.t('sessions.create_through_lti.session_with_outcome', consumer: consumer, locale: locale) } let(:message) { I18n.t('sessions.create_through_lti.session_with_outcome', consumer:, locale:) }
before do before do
allow(controller).to receive(:lti_outcome_service?).and_return(true) allow(controller).to receive(:lti_outcome_service?).and_return(true)
@ -125,7 +125,7 @@ describe SessionsController do
context 'when LTI outcomes are not supported' do context 'when LTI outcomes are not supported' do
# The expected message should be localized in the requested localization # The expected message should be localized in the requested localization
let(:message) { I18n.t('sessions.create_through_lti.session_without_outcome', consumer: consumer, locale: locale) } let(:message) { I18n.t('sessions.create_through_lti.session_without_outcome', consumer:, locale:) }
before do before do
allow(controller).to receive(:lti_outcome_service?).and_return(false) allow(controller).to receive(:lti_outcome_service?).and_return(false)

View File

@ -116,7 +116,7 @@ describe SubmissionsController do
context 'with an invalid filename' do context 'with an invalid filename' do
let(:filename) { SecureRandom.hex } let(:filename) { SecureRandom.hex }
before { get :render_file, params: {filename: filename, id: submission.id, token: token} } before { get :render_file, params: {filename:, id: submission.id, token:} }
expect_http_status(:not_found) expect_http_status(:not_found)
end end
@ -125,7 +125,7 @@ describe SubmissionsController do
let(:submission) { create(:submission, exercise: create(:audio_video)) } let(:submission) { create(:submission, exercise: create(:audio_video)) }
let(:filename) { file.name_with_extension } let(:filename) { file.name_with_extension }
before { get :render_file, params: {filename: filename, id: submission.id, token: token} } before { get :render_file, params: {filename:, id: submission.id, token:} }
context 'with a binary file' do context 'with a binary file' do
let(:file) { submission.collect_files.detect {|file| file.file_type.file_extension == '.mp4' } } let(:file) { submission.collect_files.detect {|file| file.file_type.file_extension == '.mp4' } }

View File

@ -8,7 +8,7 @@ FactoryBot.define do
trait :singleton_consumer do trait :singleton_consumer do
initialize_with do initialize_with do
Consumer.find_or_initialize_by(name: name) do |consumer| Consumer.find_or_initialize_by(name:) do |consumer|
consumer.oauth_key = SecureRandom.hex consumer.oauth_key = SecureRandom.hex
consumer.oauth_secret = SecureRandom.hex consumer.oauth_secret = SecureRandom.hex
end end

View File

@ -6,7 +6,7 @@ FactoryBot.define do
default_memory_limit default_memory_limit
default_cpu_limit default_cpu_limit
docker_image { 'hklement/ubuntu-coffee:latest' } docker_image { 'hklement/ubuntu-coffee:latest' }
file_type { association :dot_coffee, user: user } file_type { association :dot_coffee, user: }
help help
name { 'CoffeeScript' } name { 'CoffeeScript' }
network_enabled { false } network_enabled { false }
@ -22,7 +22,7 @@ FactoryBot.define do
default_memory_limit default_memory_limit
default_cpu_limit default_cpu_limit
docker_image { 'hklement/ubuntu-html:latest' } docker_image { 'hklement/ubuntu-html:latest' }
file_type { association :dot_html, user: user } file_type { association :dot_html, user: }
help help
name { 'HTML5' } name { 'HTML5' }
network_enabled { false } network_enabled { false }
@ -40,7 +40,7 @@ FactoryBot.define do
default_memory_limit default_memory_limit
default_cpu_limit default_cpu_limit
docker_image { 'openhpi/co_execenv_java:8-antlr' } docker_image { 'openhpi/co_execenv_java:8-antlr' }
file_type { association :dot_java, user: user } file_type { association :dot_java, user: }
help help
name { 'Java 8' } name { 'Java 8' }
network_enabled { false } network_enabled { false }
@ -58,7 +58,7 @@ FactoryBot.define do
default_memory_limit default_memory_limit
default_cpu_limit default_cpu_limit
docker_image { 'hklement/ubuntu-jruby:latest' } docker_image { 'hklement/ubuntu-jruby:latest' }
file_type { association :dot_rb, user: user } file_type { association :dot_rb, user: }
help help
name { 'JRuby 1.7' } name { 'JRuby 1.7' }
network_enabled { false } network_enabled { false }
@ -76,7 +76,7 @@ FactoryBot.define do
default_memory_limit default_memory_limit
default_cpu_limit default_cpu_limit
docker_image { 'hklement/ubuntu-node:latest' } docker_image { 'hklement/ubuntu-node:latest' }
file_type { association :dot_js, user: user } file_type { association :dot_js, user: }
help help
name { 'Node.js' } name { 'Node.js' }
network_enabled { false } network_enabled { false }
@ -92,7 +92,7 @@ FactoryBot.define do
default_memory_limit default_memory_limit
default_cpu_limit default_cpu_limit
docker_image { 'openhpi/co_execenv_python:3.4' } docker_image { 'openhpi/co_execenv_python:3.4' }
file_type { association :dot_py, user: user } file_type { association :dot_py, user: }
help help
name { 'Python 3.4' } name { 'Python 3.4' }
network_enabled { false } network_enabled { false }
@ -110,7 +110,7 @@ FactoryBot.define do
default_memory_limit default_memory_limit
default_cpu_limit default_cpu_limit
docker_image { 'hklement/ubuntu-ruby:latest' } docker_image { 'hklement/ubuntu-ruby:latest' }
file_type { association :dot_rb, user: user } file_type { association :dot_rb, user: }
help help
name { 'Ruby 2.2' } name { 'Ruby 2.2' }
network_enabled { false } network_enabled { false }
@ -128,7 +128,7 @@ FactoryBot.define do
default_memory_limit default_memory_limit
default_cpu_limit default_cpu_limit
docker_image { 'hklement/ubuntu-sinatra:latest' } docker_image { 'hklement/ubuntu-sinatra:latest' }
file_type { association :dot_rb, user: user } file_type { association :dot_rb, user: }
exposed_ports { [4567] } exposed_ports { [4567] }
help help
name { 'Sinatra' } name { 'Sinatra' }
@ -147,7 +147,7 @@ FactoryBot.define do
default_memory_limit default_memory_limit
default_cpu_limit default_cpu_limit
docker_image { 'hklement/ubuntu-sqlite:latest' } docker_image { 'hklement/ubuntu-sqlite:latest' }
file_type { association :dot_sql, user: user } file_type { association :dot_sql, user: }
help help
name { 'SQLite' } name { 'SQLite' }
network_enabled { false } network_enabled { false }
@ -173,6 +173,6 @@ FactoryBot.define do
end end
trait :singleton_execution_environment do trait :singleton_execution_environment do
initialize_with { ExecutionEnvironment.where(name: name).first_or_create } initialize_with { ExecutionEnvironment.where(name:).first_or_create }
end end
end end

View File

@ -9,7 +9,7 @@ def create_seed_file(exercise, path, file_attributes = {})
user: exercise.user user: exercise.user
) )
name = File.basename(path).gsub(file_extension, '') name = File.basename(path).gsub(file_extension, '')
file_attributes.merge!(file_type: file_type, name: name, path: path.split('/')[1..-2].join('/'), role: file_attributes[:role] || 'regular_file') file_attributes.merge!(file_type:, name:, path: path.split('/')[1..-2].join('/'), role: file_attributes[:role] || 'regular_file')
if file_type.binary? if file_type.binary?
file_attributes[:native_file] = File.open(SeedsHelper.seed_file_path(path), 'r') file_attributes[:native_file] = File.open(SeedsHelper.seed_file_path(path), 'r')
else else
@ -22,7 +22,7 @@ FactoryBot.define do
factory :audio_video, class: 'Exercise' do factory :audio_video, class: 'Exercise' do
created_by_teacher created_by_teacher
description { "Try HTML's audio and video capabilities." } description { "Try HTML's audio and video capabilities." }
execution_environment { association :html, user: user } execution_environment { association :html, user: }
instructions { 'Build a simple website including an HTML <audio> and <video> element. Link the following media files: chai.ogg, devstories.mp4.' } instructions { 'Build a simple website including an HTML <audio> and <video> element. Link the following media files: chai.ogg, devstories.mp4.' }
title { 'Audio & Video' } title { 'Audio & Video' }
@ -40,7 +40,7 @@ FactoryBot.define do
factory :dummy, class: 'Exercise' do factory :dummy, class: 'Exercise' do
created_by_teacher created_by_teacher
description { 'Dummy' } description { 'Dummy' }
execution_environment { association :ruby, user: user } execution_environment { association :ruby, user: }
instructions instructions
title { 'Dummy' } title { 'Dummy' }
@ -56,7 +56,7 @@ FactoryBot.define do
# attributes; `create_list`'s second argument is the number of records # attributes; `create_list`'s second argument is the number of records
# to create and we make sure the user_exercise_feedback is associated properly to the exercise # to create and we make sure the user_exercise_feedback is associated properly to the exercise
after(:create) do |exercise, evaluator| after(:create) do |exercise, evaluator|
create_list(:user_exercise_feedback, evaluator.user_feedbacks_count, exercise: exercise) create_list(:user_exercise_feedback, evaluator.user_feedbacks_count, exercise:)
end end
end end
end end
@ -64,7 +64,7 @@ FactoryBot.define do
factory :even_odd, class: 'Exercise' do factory :even_odd, class: 'Exercise' do
created_by_teacher created_by_teacher
description { 'Implement two methods even and odd which return whether a given number is even or odd, respectively.' } description { 'Implement two methods even and odd which return whether a given number is even or odd, respectively.' }
execution_environment { association :python, user: user } execution_environment { association :python, user: }
instructions instructions
title { 'Even/Odd' } title { 'Even/Odd' }
@ -78,7 +78,7 @@ FactoryBot.define do
factory :fibonacci, class: 'Exercise' do factory :fibonacci, class: 'Exercise' do
created_by_teacher created_by_teacher
description { 'Implement a recursive function that calculates a requested Fibonacci number.' } description { 'Implement a recursive function that calculates a requested Fibonacci number.' }
execution_environment { association :ruby, user: user } execution_environment { association :ruby, user: }
instructions instructions
title { 'Fibonacci Sequence' } title { 'Fibonacci Sequence' }
@ -94,7 +94,7 @@ FactoryBot.define do
factory :files, class: 'Exercise' do factory :files, class: 'Exercise' do
created_by_teacher created_by_teacher
description { 'Learn how to work with files.' } description { 'Learn how to work with files.' }
execution_environment { association :ruby, user: user } execution_environment { association :ruby, user: }
instructions instructions
title { 'Working with Files' } title { 'Working with Files' }
@ -108,7 +108,7 @@ FactoryBot.define do
factory :geolocation, class: 'Exercise' do factory :geolocation, class: 'Exercise' do
created_by_teacher created_by_teacher
description { "Use the HTML5 Geolocation API to get the user's geographical position." } description { "Use the HTML5 Geolocation API to get the user's geographical position." }
execution_environment { association :html, user: user } execution_environment { association :html, user: }
instructions instructions
title { 'Geolocation' } title { 'Geolocation' }
@ -121,7 +121,7 @@ FactoryBot.define do
factory :hello_world, class: 'Exercise' do factory :hello_world, class: 'Exercise' do
created_by_teacher created_by_teacher
description { "Write a simple 'Hello World' application." } description { "Write a simple 'Hello World' application." }
execution_environment { association :ruby, user: user } execution_environment { association :ruby, user: }
instructions instructions
title { 'Hello World' } title { 'Hello World' }
@ -134,7 +134,7 @@ FactoryBot.define do
factory :math, class: 'Exercise' do factory :math, class: 'Exercise' do
created_by_teacher created_by_teacher
description { 'Implement a recursive math library.' } description { 'Implement a recursive math library.' }
execution_environment { association :java, user: user } execution_environment { association :java, user: }
instructions instructions
title { 'Math' } title { 'Math' }
@ -149,7 +149,7 @@ FactoryBot.define do
factory :primes, class: 'Exercise' do factory :primes, class: 'Exercise' do
created_by_teacher created_by_teacher
description { 'Write a function that prints the first n prime numbers.' } description { 'Write a function that prints the first n prime numbers.' }
execution_environment { association :node_js, user: user } execution_environment { association :node_js, user: }
instructions instructions
title { 'Primes' } title { 'Primes' }
@ -161,7 +161,7 @@ FactoryBot.define do
factory :sql_select, class: 'Exercise' do factory :sql_select, class: 'Exercise' do
created_by_teacher created_by_teacher
description { 'Learn to use the SELECT statement.' } description { 'Learn to use the SELECT statement.' }
execution_environment { association :sqlite, user: user } execution_environment { association :sqlite, user: }
instructions { "Write a query which selects the full rows for all people with the last name 'Doe'." } instructions { "Write a query which selects the full rows for all people with the last name 'Doe'." }
title { 'SELECT' } title { 'SELECT' }
@ -175,7 +175,7 @@ FactoryBot.define do
factory :tdd, class: 'Exercise' do factory :tdd, class: 'Exercise' do
created_by_teacher created_by_teacher
description { 'Learn to appreciate test-driven development.' } description { 'Learn to appreciate test-driven development.' }
execution_environment { association :ruby, user: user } execution_environment { association :ruby, user: }
instructions { SeedsHelper.read_seed_file('tdd/instructions.md') } instructions { SeedsHelper.read_seed_file('tdd/instructions.md') }
title { 'Test-driven Development' } title { 'Test-driven Development' }
@ -188,7 +188,7 @@ FactoryBot.define do
factory :web_app, class: 'Exercise' do factory :web_app, class: 'Exercise' do
created_by_teacher created_by_teacher
description { 'Build a simple Web application with Sinatra.' } description { 'Build a simple Web application with Sinatra.' }
execution_environment { association :sinatra, user: user } execution_environment { association :sinatra, user: }
instructions instructions
title { 'A Simple Web Application' } title { 'A Simple Web Application' }

View File

@ -17,7 +17,7 @@ FactoryBot.define do
[ExternalUser, InternalUser].each do |klass| [ExternalUser, InternalUser].each do |klass|
trait :"singleton_#{klass.name.underscore}" do trait :"singleton_#{klass.name.underscore}" do
initialize_with { klass.where(email: email).first_or_create } initialize_with { klass.where(email:).first_or_create }
end end
end end

View File

@ -34,7 +34,7 @@ describe 'Authentication' do
end end
context 'with no authentication token' do context 'with no authentication token' do
let(:request_for_comment) { create(:rfc_with_comment, user: user) } let(:request_for_comment) { create(:rfc_with_comment, user:) }
let(:rfc_path) { request_for_comment_url(request_for_comment) } let(:rfc_path) { request_for_comment_url(request_for_comment) }
it 'denies access to the request for comment' do it 'denies access to the request for comment' do
@ -49,7 +49,7 @@ describe 'Authentication' do
context 'with an authentication token' do context 'with an authentication token' do
let(:user) { create(:learner) } let(:user) { create(:learner) }
let(:study_group) { request_for_comment.submission.study_group } let(:study_group) { request_for_comment.submission.study_group }
let(:request_for_comment) { create(:rfc_with_comment, user: user) } let(:request_for_comment) { create(:rfc_with_comment, user:) }
let(:commenting_user) { InternalUser.create(attributes_for(:teacher)) } let(:commenting_user) { InternalUser.create(attributes_for(:teacher)) }
let(:mail) { UserMailer.got_new_comment(request_for_comment.comments.first, request_for_comment, commenting_user) } let(:mail) { UserMailer.got_new_comment(request_for_comment.comments.first, request_for_comment, commenting_user) }
let(:rfc_link) { request_for_comment_url(request_for_comment, token: token.shared_secret) } let(:rfc_link) { request_for_comment_url(request_for_comment, token: token.shared_secret) }
@ -57,7 +57,7 @@ describe 'Authentication' do
before { allow(AuthenticationToken).to receive(:generate!).with(user, study_group).and_return(token).once } before { allow(AuthenticationToken).to receive(:generate!).with(user, study_group).and_return(token).once }
context 'when the token is valid' do context 'when the token is valid' do
let(:token) { create(:authentication_token, user: user, study_group: study_group) } let(:token) { create(:authentication_token, user:, study_group:) }
it 'allows access to the request for comment' do it 'allows access to the request for comment' do
mail.deliver_now mail.deliver_now
@ -68,7 +68,7 @@ describe 'Authentication' do
end end
context 'with an expired authentication token' do context 'with an expired authentication token' do
let(:token) { create(:authentication_token, :invalid, user: user, study_group: study_group) } let(:token) { create(:authentication_token, :invalid, user:, study_group:) }
it 'denies access to the request for comment' do it 'denies access to the request for comment' do
mail.deliver_now mail.deliver_now
@ -81,7 +81,7 @@ describe 'Authentication' do
end end
context 'when the authentication token is used to login' do context 'when the authentication token is used to login' do
let(:token) { create(:authentication_token, user: user, study_group: study_group) } let(:token) { create(:authentication_token, user:, study_group:) }
it 'invalidates the token on login' do it 'invalidates the token on login' do
mail.deliver_now mail.deliver_now
@ -108,14 +108,14 @@ describe 'Authentication' do
end end
context 'with an authentication token' do context 'with an authentication token' do
let(:request_for_comment) { create(:rfc_with_comment, user: user) } let(:request_for_comment) { create(:rfc_with_comment, user:) }
let(:study_group) { request_for_comment.submission.study_group } let(:study_group) { request_for_comment.submission.study_group }
let(:commenting_user) { InternalUser.create(attributes_for(:teacher)) } let(:commenting_user) { InternalUser.create(attributes_for(:teacher)) }
let(:mail) { UserMailer.got_new_comment(request_for_comment.comments.first, request_for_comment, commenting_user) } let(:mail) { UserMailer.got_new_comment(request_for_comment.comments.first, request_for_comment, commenting_user) }
let(:rfc_link) { request_for_comment_url(request_for_comment, token: token.shared_secret) } let(:rfc_link) { request_for_comment_url(request_for_comment, token: token.shared_secret) }
it 'still invalidates the token on login' do it 'still invalidates the token on login' do
token = create(:authentication_token, user: user, study_group: study_group) token = create(:authentication_token, user:, study_group:)
mail = UserMailer.got_new_comment(request_for_comment.comments.first, request_for_comment, commenting_user) mail = UserMailer.got_new_comment(request_for_comment.comments.first, request_for_comment, commenting_user)
mail.deliver_now mail.deliver_now
visit(request_for_comment_url(request_for_comment, token: token.shared_secret)) visit(request_for_comment_url(request_for_comment, token: token.shared_secret))

View File

@ -111,7 +111,7 @@ describe 'Editor', js: true do
end end
it 'contains a button for submitting the exercise' do it 'contains a button for submitting the exercise' do
submission = build(:submission, user: user, exercise: exercise) submission = build(:submission, user:, exercise:)
allow(submission).to receive(:calculate_score).and_return(scoring_response) allow(submission).to receive(:calculate_score).and_return(scoring_response)
allow(Submission).to receive(:find).and_return(submission) allow(Submission).to receive(:find).and_return(submission)
click_button(I18n.t('exercises.editor.score')) click_button(I18n.t('exercises.editor.score'))

View File

@ -4,15 +4,15 @@ require 'rails_helper'
describe 'ExternalUserStatistics', js: true do describe 'ExternalUserStatistics', js: true do
let(:learner) { create(:external_user) } let(:learner) { create(:external_user) }
let(:exercise) { create(:dummy, user: user) } let(:exercise) { create(:dummy, user:) }
let(:study_group) { create(:study_group) } let(:study_group) { create(:study_group) }
let(:password) { 'password123456' } let(:password) { 'password123456' }
before do before do
2.times { create(:submission, cause: 'autosave', user: learner, exercise: exercise, study_group: study_group) } 2.times { create(:submission, cause: 'autosave', user: learner, exercise:, study_group:) }
2.times { create(:submission, cause: 'run', user: learner, exercise: exercise, study_group: study_group) } 2.times { create(:submission, cause: 'run', user: learner, exercise:, study_group:) }
create(:submission, cause: 'assess', user: learner, exercise: exercise, study_group: study_group) create(:submission, cause: 'assess', user: learner, exercise:, study_group:)
create(:submission, cause: 'submit', user: learner, exercise: exercise, study_group: study_group) create(:submission, cause: 'submit', user: learner, exercise:, study_group:)
study_group.external_users << learner study_group.external_users << learner
study_group.internal_users << user study_group.internal_users << user
@ -27,7 +27,7 @@ describe 'ExternalUserStatistics', js: true do
end end
context 'when a admin accesses the page' do context 'when a admin accesses the page' do
let(:user) { create(:admin, password: password) } let(:user) { create(:admin, password:) }
it 'does display the option to enable autosaves' do it 'does display the option to enable autosaves' do
expect(page).to have_content(I18n.t('exercises.external_users.statistics.toggle_status_on')).or have_content(I18n.t('exercises.external_users.statistics.toggle_status_off')) expect(page).to have_content(I18n.t('exercises.external_users.statistics.toggle_status_on')).or have_content(I18n.t('exercises.external_users.statistics.toggle_status_off'))
@ -35,7 +35,7 @@ describe 'ExternalUserStatistics', js: true do
end end
context 'when a teacher accesses the page' do context 'when a teacher accesses the page' do
let(:user) { create(:teacher, password: password) } let(:user) { create(:teacher, password:) }
it 'does not display the option to enable autosaves' do it 'does not display the option to enable autosaves' do
expect(page).not_to have_content(I18n.t('exercises.external_users.statistics.toggle_status_on')) expect(page).not_to have_content(I18n.t('exercises.external_users.statistics.toggle_status_on'))

View File

@ -6,7 +6,7 @@ describe Assessor do
let(:assessor) { described_class.new(execution_environment: build(:ruby)) } let(:assessor) { described_class.new(execution_environment: build(:ruby)) }
describe '#assess' do describe '#assess' do
let(:assess) { assessor.assess(stdout: stdout) } let(:assess) { assessor.assess(stdout:) }
let(:stdout) { "Finished in 0.1 seconds (files took 0.1 seconds to load)\n2 examples, 1 failure" } let(:stdout) { "Finished in 0.1 seconds (files took 0.1 seconds to load)\n2 examples, 1 failure" }
context 'when an error occurs' do context 'when an error occurs' do
@ -39,7 +39,7 @@ describe Assessor do
describe '#calculate_score' do describe '#calculate_score' do
let(:count) { 42 } let(:count) { 42 }
let(:passed) { 17 } let(:passed) { 17 }
let(:test_outcome) { {count: count, passed: passed} } let(:test_outcome) { {count:, passed:} }
it 'returns the correct score' do it 'returns the correct score' do
expect(assessor.send(:calculate_score, test_outcome)).to eq(passed.to_f / count) expect(assessor.send(:calculate_score, test_outcome)).to eq(passed.to_f / count)

View File

@ -13,7 +13,7 @@ describe JunitAdapter do
let(:error_matches) { [] } let(:error_matches) { [] }
it 'returns the correct numbers' do it 'returns the correct numbers' do
expect(adapter.parse_output(stdout: stdout)).to eq(count: count, failed: failed, error_messages: error_matches) expect(adapter.parse_output(stdout:)).to eq(count:, failed:, error_messages: error_matches)
end end
end end
@ -22,7 +22,7 @@ describe JunitAdapter do
let(:stdout) { "OK (#{count} tests)" } let(:stdout) { "OK (#{count} tests)" }
it 'returns the correct numbers' do it 'returns the correct numbers' do
expect(adapter.parse_output(stdout: stdout)).to eq(count: count, passed: count) expect(adapter.parse_output(stdout:)).to eq(count:, passed: count)
end end
end end
end end

View File

@ -10,7 +10,7 @@ describe MochaAdapter do
describe '#parse_output' do describe '#parse_output' do
it 'returns the correct numbers' do it 'returns the correct numbers' do
expect(adapter.parse_output(stdout: stdout)).to eq(count: count, failed: failed) expect(adapter.parse_output(stdout:)).to eq(count:, failed:)
end end
end end
end end

View File

@ -11,7 +11,7 @@ describe PyUnitAdapter do
describe '#parse_output' do describe '#parse_output' do
it 'returns the correct numbers' do it 'returns the correct numbers' do
expect(adapter.parse_output(stderr: stderr)).to eq(count: count, failed: failed, error_messages: error_matches) expect(adapter.parse_output(stderr:)).to eq(count:, failed:, error_messages: error_matches)
end end
end end
end end

View File

@ -10,7 +10,7 @@ describe RspecAdapter do
describe '#parse_output' do describe '#parse_output' do
it 'returns the correct numbers' do it 'returns the correct numbers' do
expect(adapter.parse_output(stdout: stdout)).to eq(count: count, failed: failed) expect(adapter.parse_output(stdout:)).to eq(count:, failed:)
end end
end end
end end

View File

@ -145,7 +145,7 @@ describe Runner::Strategy::Poseidon do
it "returns true on status #{status}" do it "returns true on status #{status}" do
faraday_connection = instance_double Faraday::Connection faraday_connection = instance_double Faraday::Connection
allow(described_class).to receive(:http_connection).and_return(faraday_connection) allow(described_class).to receive(:http_connection).and_return(faraday_connection)
allow(faraday_connection).to receive(:put).and_return(Faraday::Response.new(status: status)) allow(faraday_connection).to receive(:put).and_return(Faraday::Response.new(status:))
expect(action.call).to be_truthy expect(action.call).to be_truthy
end end
end end
@ -154,7 +154,7 @@ describe Runner::Strategy::Poseidon do
it "raises an exception on status #{status}" do it "raises an exception on status #{status}" do
faraday_connection = instance_double Faraday::Connection faraday_connection = instance_double Faraday::Connection
allow(described_class).to receive(:http_connection).and_return(faraday_connection) allow(described_class).to receive(:http_connection).and_return(faraday_connection)
allow(faraday_connection).to receive(:put).and_return(Faraday::Response.new(status: status)) allow(faraday_connection).to receive(:put).and_return(Faraday::Response.new(status:))
expect { action.call }.to raise_exception Runner::Error::UnexpectedResponse expect { action.call }.to raise_exception Runner::Error::UnexpectedResponse
end end
end end
@ -248,7 +248,7 @@ describe Runner::Strategy::Poseidon do
.stub_request(:post, "#{described_class.config[:url]}/runners/#{runner_id}/execute") .stub_request(:post, "#{described_class.config[:url]}/runners/#{runner_id}/execute")
.with( .with(
body: { body: {
command: command, command:,
timeLimit: execution_environment.permitted_execution_time, timeLimit: execution_environment.permitted_execution_time,
privilegedExecution: execution_environment.privileged_execution, privilegedExecution: execution_environment.privileged_execution,
}, },

View File

@ -10,7 +10,7 @@ describe SqlResultSetComparatorAdapter do
let(:stdout) { "Missing tuples: [1]\nUnexpected tuples: []" } let(:stdout) { "Missing tuples: [1]\nUnexpected tuples: []" }
it 'considers the test as failed' do it 'considers the test as failed' do
expect(adapter.parse_output(stdout: stdout)).to eq(count: 1, failed: 1) expect(adapter.parse_output(stdout:)).to eq(count: 1, failed: 1)
end end
end end
@ -18,7 +18,7 @@ describe SqlResultSetComparatorAdapter do
let(:stdout) { "Missing tuples: []\nUnexpected tuples: [1]" } let(:stdout) { "Missing tuples: []\nUnexpected tuples: [1]" }
it 'considers the test as failed' do it 'considers the test as failed' do
expect(adapter.parse_output(stdout: stdout)).to eq(count: 1, failed: 1) expect(adapter.parse_output(stdout:)).to eq(count: 1, failed: 1)
end end
end end
@ -26,7 +26,7 @@ describe SqlResultSetComparatorAdapter do
let(:stdout) { "Missing tuples: []\nUnexpected tuples: []" } let(:stdout) { "Missing tuples: []\nUnexpected tuples: []" }
it 'considers the test as passed' do it 'considers the test as passed' do
expect(adapter.parse_output(stdout: stdout)).to eq(count: 1, passed: 1) expect(adapter.parse_output(stdout:)).to eq(count: 1, passed: 1)
end end
end end
end end

View File

@ -11,19 +11,19 @@ describe TestingFrameworkAdapter do
describe '#augment_output' do describe '#augment_output' do
context 'when missing the count of all tests' do context 'when missing the count of all tests' do
it 'adds the count of all tests' do it 'adds the count of all tests' do
expect(adapter.send(:augment_output, failed: failed, passed: passed)).to include(count: count) expect(adapter.send(:augment_output, failed:, passed:)).to include(count:)
end end
end end
context 'when missing the count of failed tests' do context 'when missing the count of failed tests' do
it 'adds the count of failed tests' do it 'adds the count of failed tests' do
expect(adapter.send(:augment_output, count: count, passed: passed)).to include(failed: failed) expect(adapter.send(:augment_output, count:, passed:)).to include(failed:)
end end
end end
context 'when missing the count of passed tests' do context 'when missing the count of passed tests' do
it 'adds the count of passed tests' do it 'adds the count of passed tests' do
expect(adapter.send(:augment_output, count: count, failed: failed)).to include(passed: passed) expect(adapter.send(:augment_output, count:, failed:)).to include(passed:)
end end
end end
end end
@ -42,7 +42,7 @@ describe TestingFrameworkAdapter do
describe '#test_outcome' do describe '#test_outcome' do
it 'calls the framework-specific implementation' do it 'calls the framework-specific implementation' do
allow(adapter).to receive(:parse_output).and_return(count: count, failed: failed, passed: passed) allow(adapter).to receive(:parse_output).and_return(count:, failed:, passed:)
expect(adapter).to receive(:parse_output) expect(adapter).to receive(:parse_output)
adapter.test_outcome('') adapter.test_outcome('')
end end

View File

@ -63,8 +63,8 @@ describe UserMailer do
describe '#got_new_comment' do describe '#got_new_comment' do
let(:user) { create(:learner) } let(:user) { create(:learner) }
let(:token) { AuthenticationToken.find_by(user: user) } let(:token) { AuthenticationToken.find_by(user:) }
let(:request_for_comment) { create(:rfc_with_comment, user: user) } let(:request_for_comment) { create(:rfc_with_comment, user:) }
let(:commenting_user) { InternalUser.create(attributes_for(:teacher)) } let(:commenting_user) { InternalUser.create(attributes_for(:teacher)) }
let(:mail) { described_class.got_new_comment(request_for_comment.comments.first, request_for_comment, commenting_user).deliver_now } let(:mail) { described_class.got_new_comment(request_for_comment.comments.first, request_for_comment, commenting_user).deliver_now }
@ -116,9 +116,9 @@ describe UserMailer do
describe '#got_new_comment_for_subscription' do describe '#got_new_comment_for_subscription' do
let(:user) { create(:learner) } let(:user) { create(:learner) }
let(:token) { AuthenticationToken.find_by(user: user) } let(:token) { AuthenticationToken.find_by(user:) }
let(:request_for_comment) { create(:rfc_with_comment, user: user) } let(:request_for_comment) { create(:rfc_with_comment, user:) }
let(:subscription) { Subscription.create(request_for_comment: request_for_comment, user: user, study_group_id: user.current_study_group_id) } let(:subscription) { Subscription.create(request_for_comment:, user:, study_group_id: user.current_study_group_id) }
let(:from_user) { InternalUser.create(attributes_for(:teacher)) } let(:from_user) { InternalUser.create(attributes_for(:teacher)) }
let(:mail) { described_class.got_new_comment_for_subscription(request_for_comment.comments.first, subscription, from_user).deliver_now } let(:mail) { described_class.got_new_comment_for_subscription(request_for_comment.comments.first, subscription, from_user).deliver_now }
@ -172,7 +172,7 @@ describe UserMailer do
let(:user) { create(:learner) } let(:user) { create(:learner) }
let(:receiver) { create(:teacher) } let(:receiver) { create(:teacher) }
let(:token) { AuthenticationToken.find_by(user: receiver) } let(:token) { AuthenticationToken.find_by(user: receiver) }
let(:request_for_comment) { create(:rfc_with_comment, user: user) } let(:request_for_comment) { create(:rfc_with_comment, user:) }
let(:mail) { described_class.send_thank_you_note(request_for_comment, receiver).deliver_now } let(:mail) { described_class.send_thank_you_note(request_for_comment, receiver).deliver_now }
it 'sets the correct sender' do it 'sets the correct sender' do

View File

@ -7,7 +7,7 @@ describe Exercise do
let(:users) { create_list(:external_user, 10) } let(:users) { create_list(:external_user, 10) }
def create_submissions def create_submissions
create_list(:submission, 10, cause: 'submit', exercise: exercise, score: Forgery(:basic).number, user: users.sample) create_list(:submission, 10, cause: 'submit', exercise:, score: Forgery(:basic).number, user: users.sample)
end end
it 'validates the number of main files' do it 'validates the number of main files' do
@ -113,7 +113,7 @@ describe Exercise do
it 'overwrites the supplied attributes' do it 'overwrites the supplied attributes' do
title = Forgery(:basic).text title = Forgery(:basic).text
expect(exercise.duplicate(title: title).title).to eq(title) expect(exercise.duplicate(title:).title).to eq(title)
end end
it 'duplicates all associated files' do it 'duplicates all associated files' do

View File

@ -24,7 +24,7 @@ describe InternalUser do
end end
it 'validates the confirmation of the password' do it 'validates the confirmation of the password' do
user.update(password: password, password_confirmation: '') user.update(password:, password_confirmation: '')
expect(user.errors[:password_confirmation]).to be_present expect(user.errors[:password_confirmation]).to be_present
end end
@ -40,7 +40,7 @@ describe InternalUser do
before { user.deliver_reset_password_instructions! } before { user.deliver_reset_password_instructions! }
it 'validates the confirmation of the password' do it 'validates the confirmation of the password' do
user.update(password: password, password_confirmation: '') user.update(password:, password_confirmation: '')
expect(user.errors[:password_confirmation]).to be_present expect(user.errors[:password_confirmation]).to be_present
end end
@ -54,7 +54,7 @@ describe InternalUser do
let(:user) { create(:teacher, activation_state: 'active') } let(:user) { create(:teacher, activation_state: 'active') }
it 'does not validate the confirmation of the password' do it 'does not validate the confirmation of the password' do
user.update(password: password, password_confirmation: '') user.update(password:, password_confirmation: '')
expect(user.errors[:password_confirmation]).not_to be_present expect(user.errors[:password_confirmation]).not_to be_present
end end

View File

@ -31,7 +31,7 @@ describe Runner do
describe '::strategy_class' do describe '::strategy_class' do
shared_examples 'uses the strategy defined in the constant' do |strategy, strategy_class| shared_examples 'uses the strategy defined in the constant' do |strategy, strategy_class|
let(:codeocean_config) { instance_double(CodeOcean::Config) } let(:codeocean_config) { instance_double(CodeOcean::Config) }
let(:runner_management_config) { {runner_management: {enabled: true, strategy: strategy}} } let(:runner_management_config) { {runner_management: {enabled: true, strategy:}} }
before do before do
# Ensure to reset the memorized helper # Ensure to reset the memorized helper
@ -166,7 +166,7 @@ describe Runner do
describe 'creation' do describe 'creation' do
let(:user) { create(:external_user) } let(:user) { create(:external_user) }
let(:execution_environment) { create(:ruby) } let(:execution_environment) { create(:ruby) }
let(:create_action) { -> { described_class.create(user: user, execution_environment: execution_environment) } } let(:create_action) { -> { described_class.create(user:, execution_environment:) } }
it 'requests a runner id from the runner management' do it 'requests a runner id from the runner management' do
expect(strategy_class).to receive(:request_from_management) expect(strategy_class).to receive(:request_from_management)
@ -254,7 +254,7 @@ describe Runner do
end end
context 'when a runner already exists' do context 'when a runner already exists' do
let!(:existing_runner) { create(:runner, user: user, execution_environment: exercise.execution_environment) } let!(:existing_runner) { create(:runner, user:, execution_environment: exercise.execution_environment) }
it 'returns the existing runner' do it 'returns the existing runner' do
new_runner = described_class.for(user, exercise.execution_environment) new_runner = described_class.for(user, exercise.execution_environment)

View File

@ -67,7 +67,7 @@ describe Submission do
end end
describe '#siblings' do describe '#siblings' do
let(:siblings) { described_class.find_by(user: user).siblings } let(:siblings) { described_class.find_by(user:).siblings }
let(:user) { create(:external_user) } let(:user) { create(:external_user) }
before do before do
@ -93,7 +93,7 @@ describe Submission do
context 'with no exercise feedback' do context 'with no exercise feedback' do
let(:exercise) { create(:dummy) } let(:exercise) { create(:dummy) }
let(:user) { build(:external_user, id: (11 - (exercise.created_at.to_i % 10)) % 10) } let(:user) { build(:external_user, id: (11 - (exercise.created_at.to_i % 10)) % 10) }
let(:submission) { build(:submission, exercise: exercise, user: user) } let(:submission) { build(:submission, exercise:, user:) }
it 'sends 10% of users to feedback page' do it 'sends 10% of users to feedback page' do
expect(submission.send(:redirect_to_feedback?)).to be_truthy expect(submission.send(:redirect_to_feedback?)).to be_truthy
@ -101,7 +101,7 @@ describe Submission do
it 'does not redirect other users' do it 'does not redirect other users' do
9.times do |i| 9.times do |i|
submission = build(:submission, exercise: exercise, user: build(:external_user, id: (11 - (exercise.created_at.to_i % 10)) - i - 1)) submission = build(:submission, exercise:, user: build(:external_user, id: (11 - (exercise.created_at.to_i % 10)) - i - 1))
expect(submission.send(:redirect_to_feedback?)).to be_falsey expect(submission.send(:redirect_to_feedback?)).to be_falsey
end end
end end
@ -110,7 +110,7 @@ describe Submission do
context 'with little exercise feedback' do context 'with little exercise feedback' do
let(:exercise) { create(:dummy_with_user_feedbacks) } let(:exercise) { create(:dummy_with_user_feedbacks) }
let(:user) { build(:external_user, id: (11 - (exercise.created_at.to_i % 10)) % 10) } let(:user) { build(:external_user, id: (11 - (exercise.created_at.to_i % 10)) % 10) }
let(:submission) { build(:submission, exercise: exercise, user: user) } let(:submission) { build(:submission, exercise:, user:) }
it 'sends 10% of users to feedback page' do it 'sends 10% of users to feedback page' do
expect(submission.send(:redirect_to_feedback?)).to be_truthy expect(submission.send(:redirect_to_feedback?)).to be_truthy
@ -118,7 +118,7 @@ describe Submission do
it 'does not redirect other users' do it 'does not redirect other users' do
9.times do |i| 9.times do |i|
submission = build(:submission, exercise: exercise, user: build(:external_user, id: (11 - (exercise.created_at.to_i % 10)) - i - 1)) submission = build(:submission, exercise:, user: build(:external_user, id: (11 - (exercise.created_at.to_i % 10)) - i - 1))
expect(submission.send(:redirect_to_feedback?)).to be_falsey expect(submission.send(:redirect_to_feedback?)).to be_falsey
end end
end end

View File

@ -215,7 +215,7 @@ describe ExercisePolicy do
before do before do
[admin, teacher].each do |user| [admin, teacher].each do |user|
[true, false].each do |public| [true, false].each do |public|
create(:dummy, public: public, user_id: user.id, user_type: InternalUser.name) create(:dummy, public:, user_id: user.id, user_type: InternalUser.name)
end end
end end
end end

View File

@ -15,7 +15,7 @@ require 'pundit/rspec'
# run twice. It is recommended that you do not name files matching this glob to # run twice. It is recommended that you do not name files matching this glob to
# end with _spec.rb. You can configure this pattern with with the --pattern # end with _spec.rb. You can configure this pattern with with the --pattern
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. # option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
Dir[Rails.root.join('spec/support/**/*.rb')].sort.each {|f| require f } Dir[Rails.root.join('spec/support/**/*.rb')].each {|f| require f }
# Checks for pending migrations before tests are run. # Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line. # If you are not using ActiveRecord, you can remove this line.

View File

@ -4,7 +4,7 @@ require 'rails_helper'
describe ExerciseService::CheckExternal do describe ExerciseService::CheckExternal do
describe '.new' do describe '.new' do
subject(:export_service) { described_class.new(uuid: uuid, codeharbor_link: codeharbor_link) } subject(:export_service) { described_class.new(uuid:, codeharbor_link:) }
let(:uuid) { SecureRandom.uuid } let(:uuid) { SecureRandom.uuid }
let(:codeharbor_link) { build(:codeharbor_link) } let(:codeharbor_link) { build(:codeharbor_link) }
@ -19,7 +19,7 @@ describe ExerciseService::CheckExternal do
end end
describe '#execute' do describe '#execute' do
subject(:check_external_service) { described_class.call(uuid: uuid, codeharbor_link: codeharbor_link) } subject(:check_external_service) { described_class.call(uuid:, codeharbor_link:) }
let(:uuid) { SecureRandom.uuid } let(:uuid) { SecureRandom.uuid }
let(:codeharbor_link) { build(:codeharbor_link) } let(:codeharbor_link) { build(:codeharbor_link) }
@ -38,7 +38,7 @@ describe ExerciseService::CheckExternal do
it 'submits the correct body' do it 'submits the correct body' do
expect(check_external_service).to have_requested(:post, codeharbor_link.check_uuid_url) expect(check_external_service).to have_requested(:post, codeharbor_link.check_uuid_url)
.with(body: {uuid: uuid}.to_json) .with(body: {uuid:}.to_json)
end end
context 'when response contains a JSON with expected keys' do context 'when response contains a JSON with expected keys' do

View File

@ -4,7 +4,7 @@ require 'rails_helper'
RSpec.describe ExerciseService::PushExternal do RSpec.describe ExerciseService::PushExternal do
describe '.new' do describe '.new' do
subject(:push_external) { described_class.new(zip: zip, codeharbor_link: codeharbor_link) } subject(:push_external) { described_class.new(zip:, codeharbor_link:) }
let(:zip) { ProformaService::ExportTask.call(exercise: build(:dummy)) } let(:zip) { ProformaService::ExportTask.call(exercise: build(:dummy)) }
let(:codeharbor_link) { build(:codeharbor_link) } let(:codeharbor_link) { build(:codeharbor_link) }
@ -19,14 +19,14 @@ RSpec.describe ExerciseService::PushExternal do
end end
describe '#execute' do describe '#execute' do
subject(:push_external) { described_class.call(zip: zip, codeharbor_link: codeharbor_link) } subject(:push_external) { described_class.call(zip:, codeharbor_link:) }
let(:zip) { ProformaService::ExportTask.call(exercise: build(:dummy)) } let(:zip) { ProformaService::ExportTask.call(exercise: build(:dummy)) }
let(:codeharbor_link) { build(:codeharbor_link) } let(:codeharbor_link) { build(:codeharbor_link) }
let(:status) { 200 } let(:status) { 200 }
let(:response) { '' } let(:response) { '' }
before { stub_request(:post, codeharbor_link.push_url).to_return(status: status, body: response) } before { stub_request(:post, codeharbor_link.push_url).to_return(status:, body: response) }
it 'calls the correct url' do it 'calls the correct url' do
expect(push_external).to have_requested(:post, codeharbor_link.push_url) expect(push_external).to have_requested(:post, codeharbor_link.push_url)

View File

@ -4,7 +4,7 @@ require 'rails_helper'
RSpec.describe ProformaService::ConvertExerciseToTask do RSpec.describe ProformaService::ConvertExerciseToTask do
describe '.new' do describe '.new' do
subject(:convert_to_task) { described_class.new(exercise: exercise) } subject(:convert_to_task) { described_class.new(exercise:) }
let(:exercise) { build(:dummy) } let(:exercise) { build(:dummy) }
@ -16,10 +16,10 @@ RSpec.describe ProformaService::ConvertExerciseToTask do
describe '#execute' do describe '#execute' do
subject(:task) { convert_to_task.execute } subject(:task) { convert_to_task.execute }
let(:convert_to_task) { described_class.new(exercise: exercise) } let(:convert_to_task) { described_class.new(exercise:) }
let(:exercise) do let(:exercise) do
create(:dummy, create(:dummy,
execution_environment: execution_environment, execution_environment:,
instructions: 'instruction', instructions: 'instruction',
uuid: SecureRandom.uuid, uuid: SecureRandom.uuid,
files: files + tests) files: files + tests)
@ -85,7 +85,7 @@ RSpec.describe ProformaService::ConvertExerciseToTask do
context 'when exercise has a regular file' do context 'when exercise has a regular file' do
let(:files) { [file] } let(:files) { [file] }
let(:file) { build(:file, role: 'regular_file', hidden: hidden, read_only: read_only) } let(:file) { build(:file, role: 'regular_file', hidden:, read_only:) }
let(:hidden) { true } let(:hidden) { true }
let(:read_only) { true } let(:read_only) { true }

View File

@ -4,7 +4,7 @@ require 'rails_helper'
describe ProformaService::ConvertTaskToExercise do describe ProformaService::ConvertTaskToExercise do
describe '.new' do describe '.new' do
subject(:convert_to_exercise_service) { described_class.new(task: task, user: user, exercise: exercise) } subject(:convert_to_exercise_service) { described_class.new(task:, user:, exercise:) }
let(:task) { Proforma::Task.new } let(:task) { Proforma::Task.new }
let(:user) { build(:teacher) } let(:user) { build(:teacher) }
@ -24,7 +24,7 @@ describe ProformaService::ConvertTaskToExercise do
end end
describe '#execute' do describe '#execute' do
subject(:convert_to_exercise_service) { described_class.call(task: task, user: user, exercise: exercise) } subject(:convert_to_exercise_service) { described_class.call(task:, user:, exercise:) }
before { create(:dot_txt) } before { create(:dot_txt) }
@ -36,10 +36,10 @@ describe ProformaService::ConvertTaskToExercise do
uuid: 'uuid', uuid: 'uuid',
parent_uuid: 'parent_uuid', parent_uuid: 'parent_uuid',
language: 'language', language: 'language',
meta_data: meta_data, meta_data:,
model_solutions: model_solutions, model_solutions:,
files: files, files:,
tests: tests tests:
) )
end end
let(:user) { create(:teacher) } let(:user) { create(:teacher) }
@ -63,7 +63,7 @@ describe ProformaService::ConvertTaskToExercise do
description: 'description', description: 'description',
uuid: be_blank, uuid: be_blank,
unpublished: true, unpublished: true,
user: user, user:,
files: be_empty, files: be_empty,
public: false, public: false,
hide_file_tree: false, hide_file_tree: false,
@ -80,11 +80,11 @@ describe ProformaService::ConvertTaskToExercise do
let(:meta_data) do let(:meta_data) do
{ {
CodeOcean: { CodeOcean: {
public: public, public:,
hide_file_tree: hide_file_tree, hide_file_tree:,
allow_file_creation: allow_file_creation, allow_file_creation:,
allow_auto_completion: allow_auto_completion, allow_auto_completion:,
expected_difficulty: expected_difficulty, expected_difficulty:,
execution_environment_id: execution_environment&.id, execution_environment_id: execution_environment&.id,
files: files_meta_data, files: files_meta_data,
}, },
@ -98,7 +98,7 @@ describe ProformaService::ConvertTaskToExercise do
description: 'description', description: 'description',
uuid: be_blank, uuid: be_blank,
unpublished: true, unpublished: true,
user: user, user:,
files: be_empty, files: be_empty,
public: true, public: true,
hide_file_tree: true, hide_file_tree: true,
@ -125,13 +125,13 @@ describe ProformaService::ConvertTaskToExercise do
let(:file) do let(:file) do
Proforma::TaskFile.new( Proforma::TaskFile.new(
id: 'id', id: 'id',
content: content, content:,
filename: filename, filename:,
used_by_grader: 'used_by_grader', used_by_grader: 'used_by_grader',
visible: 'yes', visible: 'yes',
usage_by_lms: usage_by_lms, usage_by_lms:,
binary: binary, binary:,
mimetype: mimetype mimetype:
) )
end end
let(:filename) { "#{path}filename.txt" } let(:filename) { "#{path}filename.txt" }
@ -192,7 +192,7 @@ describe ProformaService::ConvertTaskToExercise do
let(:content) { 'test' * (10**5) } let(:content) { 'test' * (10**5) }
it 'creates an exercise with a file that has the correct attributes' do it 'creates an exercise with a file that has the correct attributes' do
expect(convert_to_exercise_service.files.first).to have_attributes(content: content) expect(convert_to_exercise_service.files.first).to have_attributes(content:)
end end
end end

View File

@ -4,7 +4,7 @@ require 'rails_helper'
describe ProformaService::ExportTask do describe ProformaService::ExportTask do
describe '.new' do describe '.new' do
subject(:export_task) { described_class.new(exercise: exercise) } subject(:export_task) { described_class.new(exercise:) }
let(:exercise) { build(:dummy) } let(:exercise) { build(:dummy) }
@ -22,15 +22,15 @@ describe ProformaService::ExportTask do
end end
describe '#execute' do describe '#execute' do
subject(:export_task) { described_class.call(exercise: exercise) } subject(:export_task) { described_class.call(exercise:) }
let(:task) { Proforma::Task.new } let(:task) { Proforma::Task.new }
let(:exercise) { build(:dummy) } let(:exercise) { build(:dummy) }
let(:exporter) { instance_double(Proforma::Exporter, perform: 'zip') } let(:exporter) { instance_double(Proforma::Exporter, perform: 'zip') }
before do before do
allow(ProformaService::ConvertExerciseToTask).to receive(:call).with(exercise: exercise).and_return(task) allow(ProformaService::ConvertExerciseToTask).to receive(:call).with(exercise:).and_return(task)
allow(Proforma::Exporter).to receive(:new).with(task: task, custom_namespaces: [{prefix: 'CodeOcean', uri: 'codeocean.openhpi.de'}]).and_return(exporter) allow(Proforma::Exporter).to receive(:new).with(task:, custom_namespaces: [{prefix: 'CodeOcean', uri: 'codeocean.openhpi.de'}]).and_return(exporter)
end end
it do it do

View File

@ -4,7 +4,7 @@ require 'rails_helper'
describe ProformaService::Import do describe ProformaService::Import do
describe '.new' do describe '.new' do
subject(:import_service) { described_class.new(zip: zip, user: user) } subject(:import_service) { described_class.new(zip:, user:) }
let(:zip) { Tempfile.new('proforma_test_zip_file') } let(:zip) { Tempfile.new('proforma_test_zip_file') }
let(:user) { build(:teacher) } let(:user) { build(:teacher) }
@ -27,14 +27,14 @@ describe ProformaService::Import do
let(:exercise) do let(:exercise) do
create(:dummy, create(:dummy,
instructions: 'instruction', instructions: 'instruction',
execution_environment: execution_environment, execution_environment:,
files: files + tests, files: files + tests,
hide_file_tree: true, hide_file_tree: true,
allow_file_creation: false, allow_file_creation: false,
allow_auto_completion: true, allow_auto_completion: true,
expected_difficulty: 7, expected_difficulty: 7,
uuid: uuid, uuid:,
user: user) user:)
end end
let(:uuid) { nil } let(:uuid) { nil }

View File

@ -2,6 +2,6 @@
module Authentication module Authentication
def sign_in(user, password) def sign_in(user, password)
page.driver.post(sessions_url, email: user.email, password: password) page.driver.post(sessions_url, email: user.email, password:)
end end
end end