Skip to content

Commit

Permalink
Fix reputation fallback (#6422)
Browse files Browse the repository at this point in the history
  • Loading branch information
iHiD authored Oct 30, 2023
1 parent 5d22f9d commit ed2d158
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 112 deletions.
25 changes: 12 additions & 13 deletions app/commands/solution/search_via_representations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,45 +116,44 @@ class Fallback
initialize_with :exercise, :page, :per, :order, :criteria, :tags

def call
@solutions = Solution.joins(:published_exercise_representation).where(exercise:)
@representations = exercise.representations.where('num_published_solutions > 0')

sort!
filter!
paginate!

@solutions
@representations = @representations.includes(:prestigious_solution).page(page).per(per)

Kaminari.paginate_array(@representations.map(&:prestigious_solution), total_count: @representations.total_count).
page(page).per(per)
end

private
attr_reader :solutions

def filter!
# By grouping, we force MySQL to return just one result per group
@solutions = @solutions.group(:published_exercise_representation_id)

# We can't filter on criteria as code is not stored in the database

@solutions = @solutions.joins(:tags).where(tags: { tag: tags }) if tags.present?
@representations = @representations.joins(prestigious_solution: :tags).where(tags: { tag: tags }) if tags.present?
end

def sort!
case order
when :newest
@solutions = @solutions.order(id: :desc)
@representations = @representations.joins(:prestigious_solution).order('solutions.id': :desc)
when :oldest
@solutions = @solutions.order(id: :asc)
@representations = @representations.joins(:prestigious_solution).order('solutions.id': :asc)
when :fewest_loc
@solutions = @solutions.order(num_loc: :desc)
@representations = @representations.joins(:prestigious_solution).order('solutions.num_loc': :asc)
when :highest_reputation
# This is not track-specific reputation, but it's fine for the fallback
@solutions = @solutions.joins(:user).order(reputation: :desc)
@representations = @representations.joins(prestigious_solution: :user).order('users.reputation': :desc)
else # :most_popular
@solutions = @solutions.order(num_published_solutions: :desc, id: :asc)
@representations = @representations.order(num_published_solutions: :desc, id: :asc)
end
end

def paginate!
@solutions = @solutions.
@representations = @representations.
page(page).
per(per)
end
Expand Down
130 changes: 31 additions & 99 deletions test/commands/solution/search_via_representations_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -629,131 +629,63 @@ class Solution::SearchViaRepresentationsTest < ActiveSupport::TestCase

test "fallback: sort: most popular" do
exercise = create :practice_exercise
exercise_representation_1 = create(:exercise_representation, exercise:)
exercise_representation_2 = create(:exercise_representation, exercise:)

solution_1 = create :concept_solution, exercise:, published_at: 2.days.ago,
git_important_files_hash: exercise.git_important_files_hash,
published_iteration_head_tests_status: :passed,
published_exercise_representation: exercise_representation_1
submission = create :submission, solution: solution_1, tests_status: :passed
create :submission_representation, submission:, ast: exercise_representation_1.ast
create(:submission_file, submission:)
create(:iteration, solution: solution_1, submission:)

solution_2 = create :concept_solution, exercise:, published_at: 2.days.ago,
git_important_files_hash: exercise.git_important_files_hash,
published_iteration_head_tests_status: :passed,
published_exercise_representation: exercise_representation_2
submission = create :submission, solution: solution_2, tests_status: :passed
create :submission_representation, submission:, ast: exercise_representation_2.ast
create(:submission_file, submission:)
create(:iteration, solution: solution_2, submission:)

solution_3 = create :concept_solution, exercise:, published_at: 2.days.ago,
git_important_files_hash: exercise.git_important_files_hash,
published_iteration_head_tests_status: :passed,
published_exercise_representation: exercise_representation_2
submission = create :submission, solution: solution_3, tests_status: :passed
create :submission_representation, submission:, ast: exercise_representation_2.ast
create(:submission_file, submission:)
create(:iteration, solution: solution_3, submission:)

exercise_representation_1.update(num_published_solutions: 1)
exercise_representation_2.update(num_published_solutions: 2)
solution_1 = create :concept_solution, exercise:, published_at: 2.days.ago
solution_2 = create :concept_solution, exercise:, published_at: 2.days.ago
create(:exercise_representation, exercise:, num_published_solutions: 1, prestigious_solution: solution_1)
create(:exercise_representation, exercise:, num_published_solutions: 2, prestigious_solution: solution_2)

assert_equal [solution_2, solution_1], Solution::SearchViaRepresentations::Fallback.(exercise, 1, 24, :most_popular, nil, [])
end

test "fallback: sort: oldest" do
exercise = create :practice_exercise
exercise_representation_1 = create(:exercise_representation, exercise:)
exercise_representation_2 = create(:exercise_representation, exercise:)

solutions = [
exercise_representation_1,
exercise_representation_2,
exercise_representation_2
].map do |representation|
create_solution(exercise:, representation:)
end
solution_1 = create(:concept_solution, exercise:)
solution_2 = create(:concept_solution, exercise:)
create(:exercise_representation, exercise:, num_published_solutions: 1, prestigious_solution: solution_1)
create(:exercise_representation, exercise:, num_published_solutions: 1, prestigious_solution: solution_2)

assert_equal [solutions[0], solutions[1]], Solution::SearchViaRepresentations::Fallback.(exercise, 1, 24, :oldest, nil, [])
assert_equal [solution_1, solution_2], Solution::SearchViaRepresentations::Fallback.(exercise, 1, 24, :oldest, nil, [])
end

test "fallback: sort: newest" do
exercise = create :practice_exercise
exercise_representation_1 = create(:exercise_representation, exercise:)
exercise_representation_2 = create(:exercise_representation, exercise:)

solutions = [
exercise_representation_1,
exercise_representation_2,
exercise_representation_2
].map do |representation|
create_solution(exercise:, representation:)
end
solution_1 = create(:concept_solution, exercise:)
solution_2 = create(:concept_solution, exercise:)
create(:exercise_representation, exercise:, num_published_solutions: 1, prestigious_solution: solution_1)
create(:exercise_representation, exercise:, num_published_solutions: 1, prestigious_solution: solution_2)

assert_equal [solutions[1], solutions[0]], Solution::SearchViaRepresentations::Fallback.(exercise, 1, 24, :newest, nil, [])
assert_equal [solution_2, solution_1], Solution::SearchViaRepresentations::Fallback.(exercise, 1, 24, :newest, nil, [])
end

test "fallback: sort: num_loc" do
exercise = create :practice_exercise
exercise_representation_1 = create(:exercise_representation, exercise:)
exercise_representation_2 = create(:exercise_representation, exercise:)

solutions = [
[exercise_representation_1, 20],
[exercise_representation_2, 50],
[exercise_representation_2, 10]
].map do |(representation, num_loc)|
create_solution(exercise:, representation:, num_loc:)
end
solution_1 = create :concept_solution, exercise:, num_loc: 5
solution_2 = create :concept_solution, exercise:, num_loc: 2
solution_3 = create :concept_solution, exercise:, num_loc: 7
create(:exercise_representation, exercise:, num_published_solutions: 1, prestigious_solution: solution_1)
create(:exercise_representation, exercise:, num_published_solutions: 1, prestigious_solution: solution_2)
create(:exercise_representation, exercise:, num_published_solutions: 1, prestigious_solution: solution_3)

assert_equal [solutions[1], solutions[0]], Solution::SearchViaRepresentations::Fallback.(exercise, 1, 24, :fewest_loc, nil, [])
assert_equal [solution_2, solution_1, solution_3].map(&:id),
Solution::SearchViaRepresentations::Fallback.(exercise, 1, 24, :fewest_loc, nil, []).map(&:id)
end

test "fallback: sort: highest_reputation" do
user = create :user, handle: 'john', reputation: 15
other_user = create :user, handle: 'jane', reputation: 50
another_user = create :user, handle: 'june', reputation: 30
ruby = create :track, title: "Ruby"

exercise = create :practice_exercise, track: ruby
exercise_representation_1 = create(:exercise_representation, exercise:)
exercise_representation_2 = create(:exercise_representation, exercise:)

solution_1 = create :concept_solution, exercise:, published_at: 2.days.ago, user:,
git_important_files_hash: exercise.git_important_files_hash,
published_iteration_head_tests_status: :passed,
published_exercise_representation: exercise_representation_1,
num_loc: 20
submission = create :submission, solution: solution_1, tests_status: :passed
create :submission_representation, submission:, ast: exercise_representation_1.ast
create :submission_file, submission:, filename: "main.rb", content: "def my_main; end"
create(:iteration, solution: solution_1, submission:)

solution_2 = create :concept_solution, exercise:, published_at: 2.days.ago, user: other_user,
git_important_files_hash: exercise.git_important_files_hash,
published_iteration_head_tests_status: :passed,
published_exercise_representation: exercise_representation_2,
num_loc: 50
submission = create :submission, solution: solution_2, tests_status: :passed
create :submission_representation, submission:, ast: exercise_representation_2.ast
create :submission_file, submission:, filename: "main.rb", content: "def your_main; end"
create(:iteration, solution: solution_2, submission:)
exercise = create :practice_exercise

solution_3 = create :concept_solution, exercise:, published_at: 2.days.ago, user: another_user,
git_important_files_hash: exercise.git_important_files_hash,
published_iteration_head_tests_status: :passed,
published_exercise_representation: exercise_representation_2,
num_loc: 10
submission = create :submission, solution: solution_3, tests_status: :passed
create :submission_representation, submission:, ast: exercise_representation_2.ast
create :submission_file, submission:, filename: "main.rb", content: "def another_main; end"
create(:iteration, solution: solution_3, submission:)
solution_1 = create :concept_solution, exercise:, user: create(:user, reputation: 5)
solution_2 = create :concept_solution, exercise:, user: create(:user, reputation: 3)
solution_3 = create :concept_solution, exercise:, user: create(:user, reputation: 7)
create(:exercise_representation, exercise:, num_published_solutions: 1, prestigious_solution: solution_1)
create(:exercise_representation, exercise:, num_published_solutions: 1, prestigious_solution: solution_2)
create(:exercise_representation, exercise:, num_published_solutions: 1, prestigious_solution: solution_3)

assert_equal [solution_2, solution_1], Solution::SearchViaRepresentations::Fallback.(exercise, 1, 24, :highest_reputation, nil, [])
assert_equal [solution_3, solution_1, solution_2].map(&:id),
Solution::SearchViaRepresentations::Fallback.(exercise, 1, 24, :highest_reputation, nil, []).map(&:id)
end

private
Expand Down

0 comments on commit ed2d158

Please sign in to comment.