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
end
end
format.json { render json: {error: message}, status: status }
format.json { render json: {error: message}, status: }
end
end
private :render_error
def switch_locale(&action)
def switch_locale(&)
session[:locale] = sanitize_locale(params[:custom_locale] || params[:locale] || session[:locale])
locale = session[:locale] || I18n.default_locale
Sentry.set_extras(locale: locale)
I18n.with_locale(locale, &action)
Sentry.set_extras(locale:)
I18n.with_locale(locale, &)
end
private :switch_locale

View File

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

View File

@ -11,7 +11,7 @@ module CommonBehavior
notice = result if result.present?
end
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
respond_with_invalid_object(format, template: :new)
end
@ -51,7 +51,7 @@ module CommonBehavior
notice = result if result.present?
end
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
respond_with_invalid_object(format, template: :edit)
end

View File

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

View File

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

View File

@ -115,8 +115,8 @@ class ExecutionEnvironmentsController < ApplicationController
end
render locals: {
working_time_statistics: working_time_statistics,
user_statistics: user_statistics,
working_time_statistics:,
user_statistics:,
}
end
@ -132,7 +132,7 @@ class ExecutionEnvironmentsController < ApplicationController
params[:execution_environment]
.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)
.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
private :execution_environment_params

View File

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

View File

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

View File

@ -41,7 +41,7 @@ class FileTypesController < ApplicationController
end
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, "ace/mode/#{name}"]
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
# produce more relevant results
query = attributes.map(&:value).join(' ')
{submission: submission, error: error, attributes: attributes, query: query}
{submission:, error:, attributes:, query:}
end
# 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
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|
StudyGroupMembership.new(user: @user, study_group: study_group)
StudyGroupMembership.new(user: @user, study_group:)
end
end

View File

@ -26,14 +26,14 @@ class LiveStreamsController < ApplicationController
runner = Runner.for(current_user, @execution_environment)
fallback_location = shell_execution_environment_path(@execution_environment)
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
private
def send_runner_file(runner, desired_file, redirect_fallback = root_path, privileged: false)
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|
unless response.committed?
# Disable Rack::ETag, which would otherwise cause the response to be cached

View File

@ -15,7 +15,7 @@ class RemoteEvaluationController < ApplicationController
else
201
end
render json: result, status: status
render json: result, status:
end
# POST /submit
@ -29,7 +29,7 @@ class RemoteEvaluationController < ApplicationController
status = result[:status]
end
render json: result, status: status
render json: result, status:
end
def try_lti
@ -62,7 +62,7 @@ class RemoteEvaluationController < ApplicationController
def create_and_score_submission(cause)
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.calculate_score
else

View File

@ -146,7 +146,7 @@ class SubmissionsController < ApplicationController
end
else
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]}")
end
rescue JSON::ParserError => e
@ -183,19 +183,19 @@ class SubmissionsController < ApplicationController
exit_statement =
if @testrun[:output].empty? && exit_code.zero?
@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?
@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?
@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
@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
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
send_and_store client_socket, {cmd: :status, status: :out_of_memory}
@testrun[:status] = :out_of_memory
@ -307,8 +307,8 @@ class SubmissionsController < ApplicationController
exercise_id = @submission.exercise_id
remote_evaluation_mapping = RemoteEvaluationMapping.create(
user: user,
exercise_id: exercise_id,
user:,
exercise_id:,
study_group_id: session[:study_group_id]
)
@ -370,7 +370,7 @@ class SubmissionsController < ApplicationController
testrun = Testrun.create!(
file: @file,
passed: @testrun[:passed],
cause: cause,
cause:,
submission: @submission,
exit_code: @testrun[:exit_code], # might be nil, e.g., when the run did not finish
status: @testrun[:status] || :failed,
@ -379,7 +379,7 @@ class SubmissionsController < ApplicationController
waiting_for_container_time: @testrun[:waiting_for_container_time]
)
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
def send_hints(tubesock, errors)
@ -430,10 +430,10 @@ class SubmissionsController < ApplicationController
parsed[:stream] = parsed[:stream].to_sym if parsed.key? :stream
parsed
else
{cmd: :write, stream: stream, data: data}
{cmd: :write, stream:, data:}
end
rescue JSON::ParserError
{cmd: :write, stream: stream, data: data}
{cmd: :write, stream:, data:}
end
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)
if params[:subscription].present?
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
private :subscription_params

View File

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

View File

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

View File

@ -53,9 +53,9 @@ module ApplicationHelper
ActionController::Base.helpers.sanitize Kramdown::Document.new(markdown).to_html
end
def row(options = {}, &block)
def row(options = {}, &)
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

View File

@ -11,7 +11,7 @@ module AuthenticatedUrlHelper
COOKIE_EXPIRATION = 30.seconds
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
add_query_parameters(url, {TOKEN_PARAM => token})
@ -58,7 +58,7 @@ module AuthenticatedUrlHelper
def prepare_short_living_cookie(value)
{
value: value,
value:,
expires: COOKIE_EXPIRATION.from_now,
httponly: true,
same_site: :strict,

View File

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

View File

@ -40,7 +40,7 @@ module CodeOcean
scope :visible, -> { where(hidden: false) }
ROLES.each do |role|
scope :"#{role}s", -> { where(role: role) }
scope :"#{role}s", -> { where(role:) }
end
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)
{
id: id,
id:,
image: docker_image,
prewarmingPoolSize: pool_size,
cpuLimit: cpu_limit,

View File

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

View File

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

View File

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

View File

@ -19,12 +19,12 @@ class LinterCheckRun < ApplicationRecord
result: linter_result[:result],
line: linter_result[:line],
scope: linter_result[:scope],
testrun: testrun,
file: file
testrun:,
file:
)
rescue ActiveRecord::RecordInvalid
# 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

View File

@ -42,7 +42,7 @@ class ProxyExercise < ApplicationRecord
end
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
Rails.logger.debug { "retrieved assigned exercise for user #{user.id}: 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")}"
exercises.where('expected_difficulty > 1').sample # difficulty should be > 1 to prevent dummy exercise from being chosen.
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)
matching_exercise
end
@ -105,9 +105,9 @@ class ProxyExercise < ApplicationRecord
relative_knowledge_improvement[potex] = 0.0
Rails.logger.debug { "review potential exercise #{potex.id}" }
tags.each do |tag|
tag_ratio = potex.exercise_tags.find_by(tag: tag).factor.to_f / potex.exercise_tags.inject(0) do |sum, et|
sum + et.factor
end
tag_ratio = potex.exercise_tags.find_by(tag:).factor.to_f / potex.exercise_tags.inject(0) do |sum, et|
sum + et.factor
end
max_topic_knowledge_ratio = potex.expected_difficulty * tag_ratio
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)

View File

@ -31,9 +31,9 @@ class Runner < ApplicationRecord
end
def self.for(user, execution_environment)
runner = find_by(user: user, execution_environment: execution_environment)
runner = find_by(user:, execution_environment:)
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`.
raise Runner::Error::Unknown.new("Runner could not be saved: #{runner.errors.inspect}") unless runner.persisted?
else
@ -52,8 +52,8 @@ class Runner < ApplicationRecord
@strategy.copy_files(files)
end
def download_file(path, **options, &block)
@strategy.download_file(path, **options, &block)
def download_file(path, **options, &)
@strategy.download_file(path, **options, &)
end
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
# this event loop is stopped after the socket was closed.
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
raise socket.error if socket.error.present?
rescue Runner::Error => e
@ -120,7 +120,7 @@ class Runner < ApplicationRecord
save
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|
output[:stderr] << data
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
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|
StructuredErrorAttribute.create_from_template(attribute, instance, message_buffer)
end

View File

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

View File

@ -88,7 +88,7 @@ class Submission < ApplicationRecord
end
def siblings
user.submissions.where(exercise_id: exercise_id)
user.submissions.where(exercise_id:)
end
def to_s
@ -129,7 +129,7 @@ class Submission < ApplicationRecord
end
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
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.
# 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
durations = {}
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
rescue Runner::Error => e
e.waiting_duration = waiting_duration
@ -237,13 +237,13 @@ class Submission < ApplicationRecord
def command_substitutions(filename)
{
class_name: File.basename(filename, File.extname(filename)).upcase_first,
filename: filename,
filename:,
module_name: File.basename(filename, File.extname(filename)).underscore,
}
end
def score_file(output, file)
assessor = Assessor.new(execution_environment: execution_environment)
assessor = Assessor.new(execution_environment:)
assessment = assessor.assess(output)
passed = ((assessment[:passed] == assessment[:count]) and (assessment[:score]).positive?)
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(
submission: self,
cause: 'assess', # Required to differ run and assess for RfC show
file: file, # Test file that was executed
passed: passed,
file:, # Test file that was executed
passed:,
exit_code: output[:exit_code],
status: output[:status],
output: testrun_output.presence,
@ -265,7 +265,7 @@ class Submission < ApplicationRecord
waiting_for_container_time: output[:waiting_for_container_time]
)
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
@ -278,7 +278,7 @@ class Submission < ApplicationRecord
end
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)
end
@ -308,7 +308,7 @@ class Submission < ApplicationRecord
update(score: score.to_d)
if normalized_score.to_d == BigDecimal('1.0')
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.save
end

View File

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

View File

@ -17,7 +17,7 @@ class UserExerciseFeedback < ApplicationRecord
end
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
end
end

View File

@ -23,12 +23,12 @@ module ProformaService
title: @exercise.title,
description: @exercise.description,
internal_description: nil,
proglang: proglang,
proglang:,
files: task_files,
tests: tests,
uuid: uuid,
tests:,
uuid:,
language: DEFAULT_LANGUAGE,
model_solutions: model_solutions,
model_solutions:,
meta_data: {
CodeOcean: {
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_auto_completion: string_to_bool(@task.meta_data[:CodeOcean]&.dig(:allow_auto_completion)) || false,
expected_difficulty: @task.meta_data[:CodeOcean]&.dig(:expected_difficulty) || 1,
execution_environment_id: execution_environment_id,
execution_environment_id:,
files: files
files:
)
end

View File

@ -17,7 +17,7 @@ module ProformaService
exercise = base_exercise
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

View File

@ -8,7 +8,7 @@ json.download_file_url download_file_submission_path(@submission, 'a.', format:
unless @embed_options[:disable_download]
json.render_url @submission.collect_files.select(&:visible) do |files|
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.url AuthenticatedUrlHelper.sign(url, @submission)

View File

@ -1,6 +1,6 @@
# 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
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!
message = {
testrun: testrun,
testrun:,
cmd: json['cmd'],
# We cannot infer any timestamp and thus use arbitrary, distinct millisecond values (1s = 1000ms)
timestamp: ActiveSupport::Duration.build(order / 1000.0),

View File

@ -10,7 +10,7 @@ class MigratePermissionsToStudyGroup < ActiveRecord::Migration[6.1]
def create_default_groups
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}"
end
end
@ -25,7 +25,7 @@ class MigratePermissionsToStudyGroup < ActiveRecord::Migration[6.1]
# All platform admins will "just" be a teacher in the study group
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)
end
end

View File

@ -13,7 +13,7 @@ passwords = ['password', 'password confirmation'].map do |attribute|
end
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
abort('Passwords do not match!')
end

View File

@ -1,10 +1,10 @@
# frozen_string_literal: true
class CppCatch2Adapter < TestingFrameworkAdapter
ALL_PASSED_REGEXP = /in\s+(\d+)\s+test case/.freeze
COUNT_REGEXP = /test cases:\s+(\d+)/.freeze
FAILURES_REGEXP = / \|\s+(\d+)\s+failed/.freeze
ASSERTION_ERROR_REGEXP = /\n(.+)error:(.+);/.freeze
ALL_PASSED_REGEXP = /in\s+(\d+)\s+test case/
COUNT_REGEXP = /test cases:\s+(\d+)/
FAILURES_REGEXP = / \|\s+(\d+)\s+failed/
ASSERTION_ERROR_REGEXP = /\n(.+)error:(.+);/
def self.framework_name
'CppCatch2'
@ -17,7 +17,7 @@ class CppCatch2Adapter < TestingFrameworkAdapter
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
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

View File

@ -1,9 +1,9 @@
# frozen_string_literal: true
class Junit5Adapter < TestingFrameworkAdapter
COUNT_REGEXP = /(\d+) tests found/.freeze
FAILURES_REGEXP = /(\d+) tests failed/.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.freeze
COUNT_REGEXP = /(\d+) tests found/
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
def self.framework_name
'JUnit 5'
@ -13,10 +13,10 @@ class Junit5Adapter < TestingFrameworkAdapter
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
if failed.zero?
{count: count, passed: count}
{count:, passed: count}
else
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

View File

@ -1,10 +1,10 @@
# frozen_string_literal: true
class JunitAdapter < TestingFrameworkAdapter
COUNT_REGEXP = /Tests run: (\d+)/.freeze
FAILURES_REGEXP = /Failures: (\d+)/.freeze
SUCCESS_REGEXP = /OK \((\d+) tests?\)\s*(?:\x1B\]0;|exit)?\s*\z/.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.freeze
COUNT_REGEXP = /Tests run: (\d+)/
FAILURES_REGEXP = /Failures: (\d+)/
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
def self.framework_name
'JUnit 4'
@ -17,7 +17,7 @@ class JunitAdapter < TestingFrameworkAdapter
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
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

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
class MochaAdapter < TestingFrameworkAdapter
SUCCESS_REGEXP = /(\d+) passing/.freeze
FAILURES_REGEXP = /(\d+) failing/.freeze
SUCCESS_REGEXP = /(\d+) passing/
FAILURES_REGEXP = /(\d+) failing/
def self.framework_name
'Mocha'
@ -11,6 +11,6 @@ class MochaAdapter < TestingFrameworkAdapter
def parse_output(output)
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
{count: success + failed, failed: failed}
{count: success + failed, failed:}
end
end

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
class PyLintAdapter < TestingFrameworkAdapter
REGEXP = %r{Your code has been rated at (-?\d+\.?\d*)/(\d+\.?\d*)}.freeze
ASSERTION_ERROR_REGEXP = /^(.*?\.py):(\d+):(.*?)\(([^,]*?), ([^,]*?),([^,]*?)\) (.*?)$/.freeze
REGEXP = %r{Your code has been rated at (-?\d+\.?\d*)/(\d+\.?\d*)}
ASSERTION_ERROR_REGEXP = /^(.*?\.py):(\d+):(.*?)\(([^,]*?), ([^,]*?),([^,]*?)\) (.*?)$/
def self.framework_name
'PyLint'
@ -41,8 +41,8 @@ class PyLintAdapter < TestingFrameworkAdapter
end
concatenated_errors = assertion_error_matches.map {|result| "#{result[:name]}: #{result[:result]}" }
{
count: count,
failed: failed,
count:,
failed:,
error_messages: concatenated_errors.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
if captures.nil?
Sentry.capture_message({regex: regex, message: message[:result]}.to_json)
Sentry.capture_message({regex:, message: message[:result]}.to_json)
replacement = {}
else
replacement = captures.each do |key, value|
@ -100,7 +100,7 @@ class PyLintAdapter < TestingFrameworkAdapter
def self.get_t(key, default)
# key might be "linter.#{severity}.#{name}.#{key}.#{value}"
# 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
keys = cleaned_key.split('.')
final_key = keys.pop
@ -111,7 +111,7 @@ class PyLintAdapter < TestingFrameworkAdapter
# Read config key
I18n.t(keys.append('log_missing').join('.'), default: false)
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
end
end

View File

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

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
class RScriptAdapter < TestingFrameworkAdapter
REGEXP = /(\d+) examples?, (\d+) passed?/.freeze
ASSERTION_ERROR_REGEXP = /AssertionError:\s(.*)/.freeze
REGEXP = /(\d+) examples?, (\d+) passed?/
ASSERTION_ERROR_REGEXP = /AssertionError:\s(.*)/
def self.framework_name
'R Script'
@ -14,6 +14,6 @@ class RScriptAdapter < TestingFrameworkAdapter
passed = captures.second
failed = count - passed
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

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
class RspecAdapter < TestingFrameworkAdapter
REGEXP = /(\d+) examples?, (\d+) failures?/.freeze
REGEXP = /(\d+) examples?, (\d+) failures?/
def self.framework_name
'RSpec 3'
@ -11,6 +11,6 @@ class RspecAdapter < TestingFrameworkAdapter
captures = output[:stdout].scan(REGEXP).try(:last).map(&:to_i)
count = captures.first
failed = captures.second
{count: count, failed: failed}
{count:, failed:}
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.
# 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
return if response.status == 204
@ -143,8 +143,8 @@ class Runner::Strategy::Poseidon < Runner::Strategy
def retrieve_files(path: './', recursive: true, privileged_execution: false)
url = "#{runner_url}/files"
params = {
path: path,
recursive: recursive,
path:,
recursive:,
privilegedExecution: privileged_execution || @execution_environment.privileged_execution,
}
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
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)
yield(socket, starting_time)
socket
@ -293,13 +293,13 @@ class Runner::Strategy::Poseidon < Runner::Strategy
end
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
end
end
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
end
end
@ -316,7 +316,7 @@ class Runner::Strategy::Poseidon < Runner::Strategy
def execute_command(command, privileged_execution: false)
url = "#{runner_url}/execute"
body = {
command: command,
command:,
timeLimit: @execution_environment.permitted_execution_time,
privilegedExecution: privileged_execution || @execution_environment.privileged_execution,
}

View File

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

View File

@ -133,7 +133,7 @@ namespace :detect_exercise_anomalies do
segment.each do |user|
reason = "{\"segment\": \"#{key}\", \"feature\": \"#{user[:reason]}\", value: \"#{user[:value]}\"}"
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
@ -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])
host = CodeOcean::Application.config.action_mailer.default_url_options[:host]
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
end
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|
puts "Exporting exercise ##{exercise.id}"
error = ExerciseService::PushExternal.call(
zip: ProformaService::ExportTask.call(exercise: exercise),
codeharbor_link: codeharbor_link
zip: ProformaService::ExportTask.call(exercise:),
codeharbor_link:
)
if error.nil?
successful_exports << exercise.id

View File

@ -56,7 +56,7 @@ describe Lti do
it 'returns to the tool consumer' do
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'))
controller.send(:refuse_lti_launch, message: message)
controller.send(:refuse_lti_launch, message:)
end
end
@ -174,14 +174,14 @@ describe Lti do
controller.instance_variable_set(:@exercise, create(:fibonacci))
expect(controller.session).to receive(:[]=).with(:external_user_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
it 'creates an LtiParameter Object' do
before_count = LtiParameter.count
controller.instance_variable_set(:@current_user, create(:external_user))
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)
end
end

View File

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

View File

@ -30,7 +30,7 @@ describe CodeOcean::FilesController do
end
describe 'POST #create' do
let(:submission) { create(:submission, user: user) }
let(:submission) { create(:submission, user:) }
context 'with a valid file' do
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
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} }
@ -56,7 +56,7 @@ describe CodeharborLinksController do
end
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(: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
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} }
it 'deletes codeharbor_link' do

View File

@ -6,7 +6,7 @@ describe CommentsController do
render_views
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(:updated_comment) { comment.reload }
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
allow(Runner).to receive(:for).with(user, execution_environment).and_return runner
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
expect_assigns(execution_environment: :execution_environment)

View File

@ -37,7 +37,7 @@ describe ExercisesController do
expect_assigns(exercise: Exercise)
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)
end
@ -78,7 +78,7 @@ describe ExercisesController do
end
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
let(:files_attributes) { {'0' => build(:file).attributes} }
@ -89,7 +89,7 @@ describe ExercisesController do
end
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
let(:file_path) { Rails.root.join('db/seeds/audio_video/devstories.mp4') }
@ -255,14 +255,14 @@ describe ExercisesController do
end
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(:external_user) { create(:external_user) }
before do
2.times { create(:submission, cause: 'autosave', user: external_user, exercise: exercise) }
2.times { create(:submission, cause: 'run', user: external_user, exercise: exercise) }
create(:submission, cause: 'assess', 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:) }
create(:submission, cause: 'assess', user: external_user, exercise:)
end
context 'when viewing the default submission statistics page without a parameter' do
@ -312,8 +312,8 @@ describe ExercisesController do
end
before do
create(:lti_parameter, external_user: user, exercise: exercise)
submission = build(:submission, exercise: exercise, user: user)
create(:lti_parameter, external_user: user, exercise:)
submission = build(:submission, exercise:, user:)
allow(submission).to receive(:normalized_score).and_return(1)
allow(submission).to receive(:calculate_score).and_return(scoring_response)
allow(Submission).to receive(:create).and_return(submission)
@ -404,13 +404,13 @@ describe ExercisesController do
render_views
let(:post_request) { post :export_external_check, params: {id: exercise.id} }
let!(:codeharbor_link) { create(:codeharbor_link, user: user) }
let(:external_check_hash) { {message: message, uuid_found: true, update_right: update_right, error: error} }
let!(:codeharbor_link) { create(:codeharbor_link, user:) }
let(:external_check_hash) { {message:, uuid_found: true, update_right:, error:} }
let(:message) { 'message' }
let(:update_right) { true }
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
post_request
@ -457,14 +457,14 @@ describe ExercisesController do
describe 'POST #export_external_confirm' do
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(:error) { nil }
let(:zip) { 'zip' }
before do
allow(ProformaService::ExportTask).to receive(:call).with(exercise: exercise).and_return(zip)
allow(ExerciseService::PushExternal).to receive(:call).with(zip: zip, codeharbor_link: codeharbor_link).and_return(error)
allow(ProformaService::ExportTask).to receive(:call).with(exercise:).and_return(zip)
allow(ExerciseService::PushExternal).to receive(:call).with(zip:, codeharbor_link:).and_return(error)
end
it 'renders correct response' do
@ -493,9 +493,9 @@ describe ExercisesController do
describe 'POST #import_uuid_check' do
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(: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}"} }
before { request.headers.merge! headers }
@ -542,7 +542,7 @@ describe ExercisesController do
end
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(:post_request) { post :import_task, body: zip_file_content }
let(:zip_file_content) { 'zipped task xml' }
@ -560,7 +560,7 @@ describe ExercisesController do
it 'calls service' do
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
context 'when import fails with ProformaError' do

View File

@ -61,7 +61,7 @@ describe InternalUsersController do
context 'with an already activated user' do
before do
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
expect_redirect(:root)
@ -80,7 +80,7 @@ describe InternalUsersController do
end
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)
@ -92,7 +92,7 @@ describe InternalUsersController do
end
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)
@ -278,7 +278,7 @@ describe InternalUsersController do
let(:password) { 'foo' }
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 }
@ -310,7 +310,7 @@ describe InternalUsersController do
context 'without a matching password confirmation' 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
expect_assigns(user: :user)

View File

@ -19,7 +19,7 @@ describe RequestForCommentsController do
it 'shows only rfc`s belonging to selected study group' do
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])
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
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 }
context 'with valid credentials' do
before do
user.activate!
post :create, params: {email: user.email, password: password, remember_me: 1}
post :create, params: {email: user.email, password:, remember_me: 1}
end
expect_flash_message(:notice, :'sessions.create.success')
@ -113,7 +113,7 @@ describe SessionsController do
context 'when LTI outcomes are supported' do
# 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
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
# 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
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
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)
end
@ -125,7 +125,7 @@ describe SubmissionsController do
let(:submission) { create(:submission, exercise: create(:audio_video)) }
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
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
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_secret = SecureRandom.hex
end

View File

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

View File

@ -9,7 +9,7 @@ def create_seed_file(exercise, path, file_attributes = {})
user: exercise.user
)
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?
file_attributes[:native_file] = File.open(SeedsHelper.seed_file_path(path), 'r')
else
@ -22,7 +22,7 @@ FactoryBot.define do
factory :audio_video, class: 'Exercise' do
created_by_teacher
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.' }
title { 'Audio & Video' }
@ -40,7 +40,7 @@ FactoryBot.define do
factory :dummy, class: 'Exercise' do
created_by_teacher
description { 'Dummy' }
execution_environment { association :ruby, user: user }
execution_environment { association :ruby, user: }
instructions
title { 'Dummy' }
@ -56,7 +56,7 @@ FactoryBot.define do
# 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
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
@ -64,7 +64,7 @@ FactoryBot.define do
factory :even_odd, class: 'Exercise' do
created_by_teacher
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
title { 'Even/Odd' }
@ -78,7 +78,7 @@ FactoryBot.define do
factory :fibonacci, class: 'Exercise' do
created_by_teacher
description { 'Implement a recursive function that calculates a requested Fibonacci number.' }
execution_environment { association :ruby, user: user }
execution_environment { association :ruby, user: }
instructions
title { 'Fibonacci Sequence' }
@ -94,7 +94,7 @@ FactoryBot.define do
factory :files, class: 'Exercise' do
created_by_teacher
description { 'Learn how to work with files.' }
execution_environment { association :ruby, user: user }
execution_environment { association :ruby, user: }
instructions
title { 'Working with Files' }
@ -108,7 +108,7 @@ FactoryBot.define do
factory :geolocation, class: 'Exercise' do
created_by_teacher
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
title { 'Geolocation' }
@ -121,7 +121,7 @@ FactoryBot.define do
factory :hello_world, class: 'Exercise' do
created_by_teacher
description { "Write a simple 'Hello World' application." }
execution_environment { association :ruby, user: user }
execution_environment { association :ruby, user: }
instructions
title { 'Hello World' }
@ -134,7 +134,7 @@ FactoryBot.define do
factory :math, class: 'Exercise' do
created_by_teacher
description { 'Implement a recursive math library.' }
execution_environment { association :java, user: user }
execution_environment { association :java, user: }
instructions
title { 'Math' }
@ -149,7 +149,7 @@ FactoryBot.define do
factory :primes, class: 'Exercise' do
created_by_teacher
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
title { 'Primes' }
@ -161,7 +161,7 @@ FactoryBot.define do
factory :sql_select, class: 'Exercise' do
created_by_teacher
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'." }
title { 'SELECT' }
@ -175,7 +175,7 @@ FactoryBot.define do
factory :tdd, class: 'Exercise' do
created_by_teacher
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') }
title { 'Test-driven Development' }
@ -188,7 +188,7 @@ FactoryBot.define do
factory :web_app, class: 'Exercise' do
created_by_teacher
description { 'Build a simple Web application with Sinatra.' }
execution_environment { association :sinatra, user: user }
execution_environment { association :sinatra, user: }
instructions
title { 'A Simple Web Application' }

View File

@ -17,7 +17,7 @@ FactoryBot.define do
[ExternalUser, InternalUser].each do |klass|
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

View File

@ -34,7 +34,7 @@ describe 'Authentication' do
end
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) }
it 'denies access to the request for comment' do
@ -49,7 +49,7 @@ describe 'Authentication' do
context 'with an authentication token' do
let(:user) { create(:learner) }
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(: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) }
@ -57,7 +57,7 @@ describe 'Authentication' do
before { allow(AuthenticationToken).to receive(:generate!).with(user, study_group).and_return(token).once }
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
mail.deliver_now
@ -68,7 +68,7 @@ describe 'Authentication' do
end
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
mail.deliver_now
@ -81,7 +81,7 @@ describe 'Authentication' do
end
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
mail.deliver_now
@ -108,14 +108,14 @@ describe 'Authentication' do
end
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(:commenting_user) { InternalUser.create(attributes_for(:teacher)) }
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) }
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.deliver_now
visit(request_for_comment_url(request_for_comment, token: token.shared_secret))

View File

@ -111,7 +111,7 @@ describe 'Editor', js: true do
end
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(:find).and_return(submission)
click_button(I18n.t('exercises.editor.score'))

View File

@ -4,15 +4,15 @@ require 'rails_helper'
describe 'ExternalUserStatistics', js: true do
let(:learner) { create(:external_user) }
let(:exercise) { create(:dummy, user: user) }
let(:exercise) { create(:dummy, user:) }
let(:study_group) { create(:study_group) }
let(:password) { 'password123456' }
before do
2.times { create(:submission, cause: 'autosave', user: learner, exercise: exercise, study_group: study_group) }
2.times { create(:submission, cause: 'run', user: learner, exercise: exercise, study_group: study_group) }
create(:submission, cause: 'assess', user: learner, exercise: exercise, study_group: study_group)
create(:submission, cause: 'submit', 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:, study_group:) }
create(:submission, cause: 'assess', user: learner, exercise:, study_group:)
create(:submission, cause: 'submit', user: learner, exercise:, study_group:)
study_group.external_users << learner
study_group.internal_users << user
@ -27,7 +27,7 @@ describe 'ExternalUserStatistics', js: true do
end
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
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
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
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)) }
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" }
context 'when an error occurs' do
@ -39,7 +39,7 @@ describe Assessor do
describe '#calculate_score' do
let(:count) { 42 }
let(:passed) { 17 }
let(:test_outcome) { {count: count, passed: passed} }
let(:test_outcome) { {count:, passed:} }
it 'returns the correct score' do
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) { [] }
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
@ -22,7 +22,7 @@ describe JunitAdapter do
let(:stdout) { "OK (#{count} tests)" }
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

View File

@ -10,7 +10,7 @@ describe MochaAdapter do
describe '#parse_output' 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

View File

@ -11,7 +11,7 @@ describe PyUnitAdapter do
describe '#parse_output' 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

View File

@ -10,7 +10,7 @@ describe RspecAdapter do
describe '#parse_output' 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

View File

@ -145,7 +145,7 @@ describe Runner::Strategy::Poseidon do
it "returns true on status #{status}" do
faraday_connection = instance_double 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
end
end
@ -154,7 +154,7 @@ describe Runner::Strategy::Poseidon do
it "raises an exception on status #{status}" do
faraday_connection = instance_double 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
end
end
@ -248,7 +248,7 @@ describe Runner::Strategy::Poseidon do
.stub_request(:post, "#{described_class.config[:url]}/runners/#{runner_id}/execute")
.with(
body: {
command: command,
command:,
timeLimit: execution_environment.permitted_execution_time,
privilegedExecution: execution_environment.privileged_execution,
},

View File

@ -10,7 +10,7 @@ describe SqlResultSetComparatorAdapter do
let(:stdout) { "Missing tuples: [1]\nUnexpected tuples: []" }
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
@ -18,7 +18,7 @@ describe SqlResultSetComparatorAdapter do
let(:stdout) { "Missing tuples: []\nUnexpected tuples: [1]" }
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
@ -26,7 +26,7 @@ describe SqlResultSetComparatorAdapter do
let(:stdout) { "Missing tuples: []\nUnexpected tuples: []" }
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

View File

@ -11,19 +11,19 @@ describe TestingFrameworkAdapter do
describe '#augment_output' do
context 'when missing 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
context 'when missing 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
context 'when missing 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
@ -42,7 +42,7 @@ describe TestingFrameworkAdapter do
describe '#test_outcome' 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)
adapter.test_outcome('')
end

View File

@ -63,8 +63,8 @@ describe UserMailer do
describe '#got_new_comment' do
let(:user) { create(:learner) }
let(:token) { AuthenticationToken.find_by(user: user) }
let(:request_for_comment) { create(:rfc_with_comment, user: user) }
let(:token) { AuthenticationToken.find_by(user:) }
let(:request_for_comment) { create(:rfc_with_comment, user:) }
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 }
@ -116,9 +116,9 @@ describe UserMailer do
describe '#got_new_comment_for_subscription' do
let(:user) { create(:learner) }
let(:token) { AuthenticationToken.find_by(user: user) }
let(:request_for_comment) { create(:rfc_with_comment, user: user) }
let(:subscription) { Subscription.create(request_for_comment: request_for_comment, user: user, study_group_id: user.current_study_group_id) }
let(:token) { AuthenticationToken.find_by(user:) }
let(:request_for_comment) { create(:rfc_with_comment, user:) }
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(: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(:receiver) { create(:teacher) }
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 }
it 'sets the correct sender' do

View File

@ -7,7 +7,7 @@ describe Exercise do
let(:users) { create_list(:external_user, 10) }
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
it 'validates the number of main files' do
@ -113,7 +113,7 @@ describe Exercise do
it 'overwrites the supplied attributes' do
title = Forgery(:basic).text
expect(exercise.duplicate(title: title).title).to eq(title)
expect(exercise.duplicate(title:).title).to eq(title)
end
it 'duplicates all associated files' do

View File

@ -24,7 +24,7 @@ describe InternalUser do
end
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
end
@ -40,7 +40,7 @@ describe InternalUser do
before { user.deliver_reset_password_instructions! }
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
end
@ -54,7 +54,7 @@ describe InternalUser do
let(:user) { create(:teacher, activation_state: 'active') }
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
end

View File

@ -31,7 +31,7 @@ describe Runner do
describe '::strategy_class' do
shared_examples 'uses the strategy defined in the constant' do |strategy, strategy_class|
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
# Ensure to reset the memorized helper
@ -166,7 +166,7 @@ describe Runner do
describe 'creation' do
let(:user) { create(:external_user) }
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
expect(strategy_class).to receive(:request_from_management)
@ -254,7 +254,7 @@ describe Runner do
end
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
new_runner = described_class.for(user, exercise.execution_environment)

View File

@ -67,7 +67,7 @@ describe Submission do
end
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) }
before do
@ -93,7 +93,7 @@ describe Submission do
context 'with no exercise feedback' do
let(:exercise) { create(:dummy) }
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
expect(submission.send(:redirect_to_feedback?)).to be_truthy
@ -101,7 +101,7 @@ describe Submission do
it 'does not redirect other users' do
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
end
end
@ -110,7 +110,7 @@ describe Submission do
context 'with little exercise feedback' do
let(:exercise) { create(:dummy_with_user_feedbacks) }
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
expect(submission.send(:redirect_to_feedback?)).to be_truthy
@ -118,7 +118,7 @@ describe Submission do
it 'does not redirect other users' do
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
end
end

View File

@ -215,7 +215,7 @@ describe ExercisePolicy do
before do
[admin, teacher].each do |user|
[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

View File

@ -15,7 +15,7 @@ require 'pundit/rspec'
# 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
# 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.
# 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 '.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(:codeharbor_link) { build(:codeharbor_link) }
@ -19,7 +19,7 @@ describe ExerciseService::CheckExternal do
end
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(:codeharbor_link) { build(:codeharbor_link) }
@ -38,7 +38,7 @@ describe ExerciseService::CheckExternal do
it 'submits the correct body' do
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
context 'when response contains a JSON with expected keys' do

View File

@ -4,7 +4,7 @@ require 'rails_helper'
RSpec.describe ExerciseService::PushExternal 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(:codeharbor_link) { build(:codeharbor_link) }
@ -19,14 +19,14 @@ RSpec.describe ExerciseService::PushExternal do
end
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(:codeharbor_link) { build(:codeharbor_link) }
let(:status) { 200 }
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
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
describe '.new' do
subject(:convert_to_task) { described_class.new(exercise: exercise) }
subject(:convert_to_task) { described_class.new(exercise:) }
let(:exercise) { build(:dummy) }
@ -16,10 +16,10 @@ RSpec.describe ProformaService::ConvertExerciseToTask do
describe '#execute' do
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
create(:dummy,
execution_environment: execution_environment,
execution_environment:,
instructions: 'instruction',
uuid: SecureRandom.uuid,
files: files + tests)
@ -85,7 +85,7 @@ RSpec.describe ProformaService::ConvertExerciseToTask do
context 'when exercise has a regular file' do
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(:read_only) { true }

View File

@ -4,7 +4,7 @@ require 'rails_helper'
describe ProformaService::ConvertTaskToExercise 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(:user) { build(:teacher) }
@ -24,7 +24,7 @@ describe ProformaService::ConvertTaskToExercise do
end
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) }
@ -36,10 +36,10 @@ describe ProformaService::ConvertTaskToExercise do
uuid: 'uuid',
parent_uuid: 'parent_uuid',
language: 'language',
meta_data: meta_data,
model_solutions: model_solutions,
files: files,
tests: tests
meta_data:,
model_solutions:,
files:,
tests:
)
end
let(:user) { create(:teacher) }
@ -63,7 +63,7 @@ describe ProformaService::ConvertTaskToExercise do
description: 'description',
uuid: be_blank,
unpublished: true,
user: user,
user:,
files: be_empty,
public: false,
hide_file_tree: false,
@ -80,11 +80,11 @@ describe ProformaService::ConvertTaskToExercise do
let(:meta_data) do
{
CodeOcean: {
public: public,
hide_file_tree: hide_file_tree,
allow_file_creation: allow_file_creation,
allow_auto_completion: allow_auto_completion,
expected_difficulty: expected_difficulty,
public:,
hide_file_tree:,
allow_file_creation:,
allow_auto_completion:,
expected_difficulty:,
execution_environment_id: execution_environment&.id,
files: files_meta_data,
},
@ -98,7 +98,7 @@ describe ProformaService::ConvertTaskToExercise do
description: 'description',
uuid: be_blank,
unpublished: true,
user: user,
user:,
files: be_empty,
public: true,
hide_file_tree: true,
@ -125,13 +125,13 @@ describe ProformaService::ConvertTaskToExercise do
let(:file) do
Proforma::TaskFile.new(
id: 'id',
content: content,
filename: filename,
content:,
filename:,
used_by_grader: 'used_by_grader',
visible: 'yes',
usage_by_lms: usage_by_lms,
binary: binary,
mimetype: mimetype
usage_by_lms:,
binary:,
mimetype:
)
end
let(:filename) { "#{path}filename.txt" }
@ -192,7 +192,7 @@ describe ProformaService::ConvertTaskToExercise do
let(:content) { 'test' * (10**5) }
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

View File

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

View File

@ -4,7 +4,7 @@ require 'rails_helper'
describe ProformaService::Import 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(:user) { build(:teacher) }
@ -27,14 +27,14 @@ describe ProformaService::Import do
let(:exercise) do
create(:dummy,
instructions: 'instruction',
execution_environment: execution_environment,
execution_environment:,
files: files + tests,
hide_file_tree: true,
allow_file_creation: false,
allow_auto_completion: true,
expected_difficulty: 7,
uuid: uuid,
user: user)
uuid:,
user:)
end
let(:uuid) { nil }

View File

@ -2,6 +2,6 @@
module Authentication
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