@@ -3368,6 +3368,255 @@ defmodule Cadet.AssessmentsTest do
33683368 end
33693369 end
33703370
3371+ describe "fetch_contest_voting_assesment_id function" do
3372+ test "correctly fetches voting assessment id when contest exists" do
3373+ course = insert ( :course )
3374+ config = insert ( :assessment_config )
3375+
3376+ contest_assessment = insert ( :assessment , % { course: course , config: config } )
3377+ voting_assessment = insert ( :assessment , % { course: course , config: config } )
3378+
3379+ contest_question = insert ( :programming_question , assessment: contest_assessment )
3380+ voting_question = insert ( :voting_question , % {
3381+ assessment: voting_assessment ,
3382+ question: build ( :voting_question_content , contest_number: contest_assessment . number )
3383+ } )
3384+
3385+ result = Assessments . fetch_contest_voting_assesment_id ( voting_assessment . id )
3386+
3387+ assert result == contest_assessment . id
3388+ end
3389+
3390+ test "returns nil when assessment does not exist" do
3391+ non_existent_id = 999_999
3392+ result = Assessments . fetch_contest_voting_assesment_id ( non_existent_id )
3393+ assert is_nil ( result )
3394+ end
3395+
3396+ test "returns nil when no contest number matches" do
3397+ course = insert ( :course )
3398+ config = insert ( :assessment_config )
3399+
3400+ voting_assessment = insert ( :assessment , % { course: course , config: config } )
3401+
3402+ insert ( :voting_question , % {
3403+ assessment: voting_assessment ,
3404+ question: build ( :voting_question_content , contest_number: "non_existent_number" )
3405+ } )
3406+
3407+ result = Assessments . fetch_contest_voting_assesment_id ( voting_assessment . id )
3408+
3409+ assert is_nil ( result )
3410+ end
3411+ end
3412+
3413+ describe "fetch_all_contests function" do
3414+ test "fetches all contests for a course" do
3415+ course = insert ( :course )
3416+ config = insert ( :assessment_config , % { type: "Contests" } )
3417+
3418+ contest_assessment_1 = insert ( :assessment , % {
3419+ course: course ,
3420+ config: config ,
3421+ is_published: true ,
3422+ title: "Contest 1"
3423+ } )
3424+ contest_assessment_2 = insert ( :assessment , % {
3425+ course: course ,
3426+ config: config ,
3427+ is_published: false ,
3428+ title: "Contest 2"
3429+ } )
3430+
3431+ voting_assessment = insert ( :assessment , % { course: course } )
3432+
3433+ insert ( :voting_question , % {
3434+ assessment: voting_assessment ,
3435+ question: build ( :voting_question_content , contest_number: contest_assessment_1 . number )
3436+ } )
3437+ insert ( :voting_question , % {
3438+ assessment: voting_assessment ,
3439+ question: build ( :voting_question_content , contest_number: contest_assessment_2 . number )
3440+ } )
3441+
3442+ result = Assessments . fetch_all_contests ( course . id )
3443+
3444+ assert length ( result ) == 2
3445+ assert Enum . find ( result , fn c -> c . contest_id == contest_assessment_1 . id end ) . published == true
3446+ assert Enum . find ( result , fn c -> c . contest_id == contest_assessment_2 . id end ) . published == false
3447+ end
3448+
3449+ test "returns empty list when no voting questions exist" do
3450+ course = insert ( :course )
3451+ result = Assessments . fetch_all_contests ( course . id )
3452+ assert result == [ ]
3453+ end
3454+
3455+ test "excludes contests that are not of type Contests" do
3456+ course = insert ( :course )
3457+ non_contest_config = insert ( :assessment_config , % { type: "Mission" } )
3458+
3459+ non_contest_assessment = insert ( :assessment , % {
3460+ course: course ,
3461+ config: non_contest_config ,
3462+ is_published: true
3463+ } )
3464+
3465+ voting_assessment = insert ( :assessment , % { course: course } )
3466+
3467+ insert ( :voting_question , % {
3468+ assessment: voting_assessment ,
3469+ question: build ( :voting_question_content , contest_number: non_contest_assessment . number )
3470+ } )
3471+
3472+ result = Assessments . fetch_all_contests ( course . id )
3473+
3474+ assert result == [ ]
3475+ end
3476+ end
3477+
3478+ describe "fetch_top_relative_score_answers ranking" do
3479+ test "correctly ranks answers with RANK() OVER function" do
3480+ course = insert ( :course )
3481+ config = insert ( :assessment_config )
3482+ contest_assessment = insert ( :assessment , % { course: course , config: config } )
3483+ contest_question = insert ( :programming_question , assessment: contest_assessment )
3484+ voting_assessment = insert ( :assessment , % { course: course , config: config } )
3485+ voting_question = insert ( :voting_question , assessment: voting_assessment )
3486+
3487+ # generate 5 students with answers having different relative scores
3488+ student_list = insert_list ( 5 , :course_registration , % { course: course , role: :student } )
3489+
3490+ submission_list =
3491+ Enum . map (
3492+ student_list ,
3493+ fn student ->
3494+ insert (
3495+ :submission ,
3496+ student: student ,
3497+ assessment: contest_assessment ,
3498+ status: "submitted"
3499+ )
3500+ end
3501+ )
3502+
3503+ ans_list =
3504+ Enum . map (
3505+ Enum . with_index ( submission_list ) ,
3506+ fn { submission , index } ->
3507+ insert (
3508+ :answer ,
3509+ answer: build ( :programming_answer ) ,
3510+ submission: submission ,
3511+ question: contest_question ,
3512+ relative_score: 10 - index
3513+ )
3514+ end
3515+ )
3516+
3517+ top_2 = Assessments . fetch_top_relative_score_answers ( contest_question . id , 2 )
3518+
3519+ assert length ( top_2 ) == 2
3520+ assert Enum . all? ( top_2 , fn ans -> ans . rank <= 2 end )
3521+ assert Enum . map ( top_2 , fn ans -> ans . relative_score end ) == [ 10.0 , 9.0 ]
3522+ end
3523+
3524+ test "handles tied scores correctly with RANK() OVER" do
3525+ course = insert ( :course )
3526+ config = insert ( :assessment_config )
3527+ contest_assessment = insert ( :assessment , % { course: course , config: config } )
3528+ contest_question = insert ( :programming_question , assessment: contest_assessment )
3529+ voting_assessment = insert ( :assessment , % { course: course , config: config } )
3530+ voting_question = insert ( :voting_question , assessment: voting_assessment )
3531+
3532+ student_list = insert_list ( 3 , :course_registration , % { course: course , role: :student } )
3533+
3534+ submission_list =
3535+ Enum . map (
3536+ student_list ,
3537+ fn student ->
3538+ insert (
3539+ :submission ,
3540+ student: student ,
3541+ assessment: contest_assessment ,
3542+ status: "submitted"
3543+ )
3544+ end
3545+ )
3546+
3547+ # Two answers with same relative_score (tied for first)
3548+ insert ( :answer , % {
3549+ answer: build ( :programming_answer ) ,
3550+ submission: Enum . at ( submission_list , 0 ) ,
3551+ question: contest_question ,
3552+ relative_score: 10.0
3553+ } )
3554+ insert ( :answer , % {
3555+ answer: build ( :programming_answer ) ,
3556+ submission: Enum . at ( submission_list , 1 ) ,
3557+ question: contest_question ,
3558+ relative_score: 10.0
3559+ } )
3560+ insert ( :answer , % {
3561+ answer: build ( :programming_answer ) ,
3562+ submission: Enum . at ( submission_list , 2 ) ,
3563+ question: contest_question ,
3564+ relative_score: 9.0
3565+ } )
3566+
3567+ top_2 = Assessments . fetch_top_relative_score_answers ( contest_question . id , 2 )
3568+
3569+ assert length ( top_2 ) == 2
3570+ assert Enum . count ( top_2 , fn ans -> ans . rank == 1 end ) == 2
3571+ end
3572+ end
3573+
3574+ describe "fetch_top_popular_score_answers ranking" do
3575+ test "correctly ranks answers with RANK() OVER function" do
3576+ course = insert ( :course )
3577+ config = insert ( :assessment_config )
3578+ contest_assessment = insert ( :assessment , % { course: course , config: config } )
3579+ contest_question = insert ( :programming_question , assessment: contest_assessment )
3580+ voting_assessment = insert ( :assessment , % { course: course , config: config } )
3581+ voting_question = insert ( :voting_question , assessment: voting_assessment )
3582+
3583+ student_list = insert_list ( 5 , :course_registration , % { course: course , role: :student } )
3584+
3585+ submission_list =
3586+ Enum . map (
3587+ student_list ,
3588+ fn student ->
3589+ insert (
3590+ :submission ,
3591+ student: student ,
3592+ assessment: contest_assessment ,
3593+ status: "submitted"
3594+ )
3595+ end
3596+ )
3597+
3598+ ans_list =
3599+ Enum . map (
3600+ Enum . with_index ( submission_list ) ,
3601+ fn { submission , index } ->
3602+ insert (
3603+ :answer ,
3604+ answer: build ( :programming_answer ) ,
3605+ submission: submission ,
3606+ question: contest_question ,
3607+ popular_score: 20 - index
3608+ )
3609+ end
3610+ )
3611+
3612+ top_3 = Assessments . fetch_top_popular_score_answers ( contest_question . id , 3 )
3613+
3614+ assert length ( top_3 ) == 3
3615+ assert Enum . all? ( top_3 , fn ans -> ans . rank <= 3 end )
3616+ assert Enum . map ( top_3 , fn ans -> ans . popular_score end ) == [ 20.0 , 19.0 , 18.0 ]
3617+ end
3618+ end
3619+
33713620 defp get_answer_relative_scores ( answers ) do
33723621 answers |> Enum . map ( fn ans -> ans . relative_score end )
33733622 end
0 commit comments