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