def test_multiple_in_question_set(self):
        
        self.qsa1.question_set=3
        self.qsa1.save()
        self.qsa2.question_set=7
        self.qsa2.save()
        self.qsa3.question_set=3
        self.qsa3.save()
        self.qsa4.question_set=7
        self.qsa4.save()
        
        valid_options=[[self.q1,self.q2],[self.q2,self.q1],[self.q1,self.q4],[self.q4,self.q1],
                       [self.q3,self.q2],[self.q2,self.q3],[self.q3,self.q4],[self.q4,self.q3]]

        options_used = [False, False, False, False,
                        False, False, False, False]

        for j in range(200):
            question_list = get_question_list(self.asmt, rng=self.rng,
                                              seed=get_new_seed(self.rng))
            question_list = render_question_list(
                self.asmt, rng=self.rng, question_list = question_list,
                assessment_seed=get_new_seed(self.rng))
            questions = [ql['question'] for ql in question_list]
            
            self.assertTrue(questions in valid_options)
            
            one_used = valid_options.index(questions)
            options_used[one_used]=True
            
            if False not in options_used:
                break

        self.assertTrue(False not in options_used)
    def test_solution(self):
        
        self.qsa1.question_set=3
        self.qsa1.save()
        self.qsa2.question_set=7
        self.qsa2.save()
        self.qsa3.question_set=3
        self.qsa3.save()
        self.qsa4.question_set=7
        self.qsa4.save()
        
        valid_options=[[self.q1,self.q2],[self.q2,self.q1],[self.q1,self.q4],[self.q4,self.q1],
                       [self.q3,self.q2],[self.q2,self.q3],[self.q3,self.q4],[self.q4,self.q3]]


        qs = [self.q1, self.q2, self.q3, self.q4]

        for j in range(3):
            question_list = get_question_list(self.asmt, rng=self.rng,
                                              seed=get_new_seed(self.rng))
            question_list = render_question_list(
                self.asmt, rng=self.rng, question_list = question_list,
                assessment_seed=get_new_seed(self.rng), solution=True)
            questions = [ql['question'] for ql in question_list]

            self.assertTrue(questions in valid_options)
            
            for (i,question_dict) in enumerate(question_list):
                self.assertEqual(
                    question_dict['question_data']['rendered_text'],
                    "Question number %i solution."
                    % (qs.index(question_dict['question'])+1))
    def test_no_question_groups_all_orders(self):
        self.qsa4.delete()
        
        qs = [self.q1, self.q2, self.q3, self.q4]
        valid_orders = []
        orders_used = []
        for i in range(3):
            for j in range(3):
                if i==j:
                    continue
                for k in range(3):
                    if k==i or k==j:
                        continue
                    valid_orders.append([qs[i], qs[j], qs[k]])
                    orders_used.append(False)

        for i in range(200):
            question_list = get_question_list(self.asmt, rng=self.rng,
                                              seed=get_new_seed(self.rng))
            question_list = render_question_list(
                self.asmt, rng=self.rng, question_list = question_list,
                assessment_seed=get_new_seed(self.rng))
            for question_dict in question_list:
                self.assertEqual(question_dict['relative_weight'],1/3)
                self.assertFalse(question_dict['previous_same_group'])
            questions = [ql['question'] for ql in question_list]
            self.assertTrue(questions in valid_orders)
            one_used = valid_orders.index(questions)
            orders_used[one_used]=True
            
            if False not in orders_used:
                break

        self.assertTrue(False not in orders_used)
    def test_groups_fixed_order(self):
        self.asmt.fixed_order=True
        self.asmt.save()

        self.asmt.questionsetdetail_set.create(question_set=1,
                                               group="apple")
        self.asmt.questionsetdetail_set.create(question_set=4,
                                               group="apple")
        for i in range(3):
            question_list = get_question_list(self.asmt, rng=self.rng,
                                              seed=get_new_seed(self.rng))
            question_list = render_question_list(
                self.asmt, rng=self.rng, question_list = question_list,
                assessment_seed=get_new_seed(self.rng))
            questions = [ql['question'] for ql in question_list]
            self.assertEqual(questions, [self.q1,self.q2,self.q3,self.q4])
            psg = [ql['previous_same_group'] for ql in question_list]
            self.assertEqual(psg, [False,False,False,False])
            groups = [ql['group'] for ql in question_list]
            self.assertEqual(groups[0], "apple")
            self.assertEqual(groups[3], "apple")


        self.asmt.questionsetdetail_set.create(question_set=2,
                                               group="appl")
        self.asmt.questionsetdetail_set.create(question_set=3,
                                               group="appl")

        for i in range(3):
            question_list = get_question_list(self.asmt, rng=self.rng,
                                              seed=get_new_seed(self.rng))
            question_list = render_question_list(
                self.asmt, rng=self.rng, question_list = question_list,
                assessment_seed=get_new_seed(self.rng))
            questions = [ql['question'] for ql in question_list]
            self.assertEqual(questions, [self.q1,self.q2,self.q3,self.q4])
            psg = [ql['previous_same_group'] for ql in question_list]
            self.assertEqual(psg, [False,False,True,False])
            groups = [ql['group'] for ql in question_list]
            self.assertEqual(groups, ["apple", "appl", "appl", "apple"])
    def test_no_question_groups_fixed_order(self):
        self.asmt.fixed_order=True
        self.asmt.save()

        qs = [self.q1, self.q2, self.q3, self.q4]
        for j in range(10):
            question_list = get_question_list(self.asmt, rng=self.rng,
                                              seed=get_new_seed(self.rng))
            question_list = render_question_list(
                self.asmt, rng=self.rng, question_list = question_list,
                assessment_seed=get_new_seed(self.rng))
            for (i,question_dict) in enumerate(question_list):
                self.assertEqual(question_dict['question'], qs[i])
                self.assertEqual(question_dict['question_set'], i+1)
                self.assertEqual(question_dict['relative_weight'],1/4)
                qseed = int(question_dict['seed'])
                self.assertTrue(qseed >= 0 and qseed < 100000000000)
                self.assertEqual(question_dict['group'],"")
                self.assertEqual(
                    question_dict['question_data']['rendered_text'],
                    "Question number %s text." % (i+1))
                self.assertFalse(question_dict['previous_same_group'])
    def test_groups_random_order(self):
        self.asmt.questionsetdetail_set.create(question_set=1,
                                               group="apple")
        self.asmt.questionsetdetail_set.create(question_set=4,
                                               group="apple")
        qs = [self.q1, self.q2, self.q3, self.q4]
        for j in range(10):
            question_list = get_question_list(self.asmt, rng=self.rng,
                                              seed=get_new_seed(self.rng))
            question_list = render_question_list(
                self.asmt, rng=self.rng, question_list = question_list,
                assessment_seed=get_new_seed(self.rng))
            hit_first_group_member=False
            expected_next_group_member=None
            for (i,question_dict) in enumerate(question_list):
                if hit_first_group_member:
                    self.assertTrue(question_dict['previous_same_group'])
                    self.assertEqual(question_dict['group'],'apple')
                    self.assertEqual(qs.index(question_dict['question'])+1, 
                                     expected_next_group_member)
                    hit_first_group_member = False
                        
                else:
                    self.assertFalse(question_dict['previous_same_group'])
                    if question_dict['group'] == 'apple':
                        hit_first_group_member = True
                        if qs.index(question_dict['question']) == 0:
                            expected_next_group_member = 4
                        else:
                            expected_next_group_member = 1

                self.assertEqual(
                    question_dict['question_data']['rendered_text'],
                    "Question number %i text." % (qs.index(question_dict['question'])+1))


        self.asmt.questionsetdetail_set.create(question_set=2,
                                               group="appl")
        self.asmt.questionsetdetail_set.create(question_set=3,
                                               group="appl")

        for j in range(10):
            question_list = get_question_list(self.asmt, rng=self.rng,
                                              seed=get_new_seed(self.rng))
            question_list = render_question_list(
                self.asmt, rng=self.rng, question_list = question_list,
                assessment_seed=get_new_seed(self.rng))
            hit_first_group_member=False
            expected_next_group_member=None
            for (i,question_dict) in enumerate(question_list):
                if hit_first_group_member:
                    self.assertTrue(question_dict['previous_same_group'])
                    self.assertEqual(question_dict['group'],group_found)
                    self.assertEqual(qs.index(question_dict['question'])+1, 
                                     expected_next_group_member)
                    hit_first_group_member = False
                        
                else:
                    self.assertFalse(question_dict['previous_same_group'])
                    group_found = question_dict['group']
                    if group_found == 'apple':
                        hit_first_group_member = True
                        if qs.index(question_dict['question']) == 0:
                            expected_next_group_member = 4
                        else:
                            expected_next_group_member = 1
                    elif group_found == 'appl':
                        hit_first_group_member = True
                        if qs.index(question_dict['question']) == 1:
                            expected_next_group_member = 3
                        else:
                            expected_next_group_member = 2
                        
                self.assertEqual(
                    question_dict['question_data']['rendered_text'],
                    "Question number %s text." % (qs.index(question_dict['question'])+1))
    def get_context_data(self, **kwargs):
        context = super(AssessmentView, self).get_context_data(**kwargs)


        from midocs.functions import return_new_auxiliary_data
        auxiliary_data =  return_new_auxiliary_data()
        context['_auxiliary_data_'] = auxiliary_data

        import random
        rng=random.Random()

        # show post user response errors only if instructor permissions
        if user_has_given_assessment_permission_level(
                self.request.user, 2):
            show_post_user_errors=True
        else:
            show_post_user_errors=False

        from micourses.render_assessments import render_question_list
        rendered_list=render_question_list(
            self.assessment, self.question_list, rng=rng, 
            assessment_seed=self.assessment_seed, 
            user=self.request.user, 
            solution=self.solution,
            auxiliary_data = auxiliary_data,
            show_post_user_errors=show_post_user_errors)

        # if question_only is set, then view only that question
        if self.kwargs.get('question_only'):
            question_only = int(self.kwargs['question_only'])
            rendered_list=rendered_list[question_only-1:question_only]
            context['question_only'] = question_only
        context['rendered_list'] = rendered_list

        context['seed'] = self.assessment_seed

        # determine if there were any errors
        success=True
        question_errors=[]
        for (ind,q) in enumerate(rendered_list):
            if not q["question_data"]["success"]:
                success=False
                question_errors.append(str(ind+1))
        if not success:
            context['error_message'] = \
                "Errors occurred in the following questions: %s" %\
                ", ".join(question_errors)

        context['success'] = success
        
        context['generate_course_attempt_link'] = False
        context['show_solution_link'] = False

        course = self.assessment.course
        context['course'] = course
        
        if user_can_administer_assessment(self.request.user, course=course):
            if self.thread_content:
                context['generate_course_attempt_link'] = True
            if not self.solution:
                context['show_solution_link'] = True

        if self.thread_content:
            context['assessment_name'] = self.thread_content.get_title()
        else:
            context['assessment_name'] = self.assessment.name
        if self.solution:
            context['assessment_name'] += " solution"
        context['assessment_short_name'] = self.assessment.return_short_name()
        if self.solution:
            context['assessment_short_name'] += " sol."

        if self.version:
            context['version'] =  self.version
            context['assessment_name_with_version'] = "%s, version %s" % \
                        (context['assessment_name'], context['version'])
            context['assessment_short_name_with_version'] = "%s, version %s" % \
                        (context['assessment_short_name'], context['version'])
        else:
            context['version'] = ''
            context['assessment_name_with_version'] = context['assessment_name']
            context['assessment_short_name_with_version'] \
                = context['assessment_short_name']

        if self.course_enrollment and self.thread_content:
            if self.course_enrollment.role == STUDENT_ROLE and self.current_attempt:
                due = self.thread_content.get_adjusted_due(
                    self.current_attempt.record)

                if course.adjust_due_attendance and due:
                    due_date_url = reverse(
                        'micourses:adjusted_due_calculation',
                        kwargs={'course_code': course.code,
                                'content_id': self.thread_content.id }
                    )
                    from micourses.utils import format_datetime
                    current_tz = timezone.get_current_timezone()
                    due_string = format_datetime(current_tz.normalize(
                        due.astimezone(current_tz)))
                    due = mark_safe('<a href="%s">%s</a>' % \
                                               (due_date_url, due_string))
                context['due'] = due
            else:
                context['due'] = self.thread_content.get_adjusted_due()

        context['thread_content'] = self.thread_content
        context['number_in_thread'] = self.number_in_thread
        context['current_attempt'] = self.current_attempt

        context['users attempt'] = False
        context['multiple_attempts'] = False
        context['attempt_url']=None
        context['record_url']=None


        # set date from current_attempt, else as now
        if self.current_attempt:
            context['assessment_date'] = self.current_attempt.attempt_began
        else:
            context['assessment_date'] = timezone.now()


        # Check if have current attempt that belongs to user
        # (so can show score)
        # Create links to record and attempts (if valid)

        if self.current_attempt and \
           self.current_attempt.record.enrollment == self.course_enrollment:

            context['users_attempt'] = True

            valid_attempt_list = list(
                self.current_attempt.record.attempts.filter(valid=True))
            context['multiple_attempts'] = len(valid_attempt_list)>1

            context['record_url'] = reverse(
                'micourses:content_record',
                kwargs={'course_code': course.code,
                        'content_id': self.thread_content.id})

            if self.current_attempt.valid:
                attempt_number = valid_attempt_list.index(self.current_attempt)\
                                 +1
                context['attempt_url'] = reverse(
                    'micourses:content_attempt', 
                    kwargs={'course_code': course.code,
                            'content_id': self.thread_content.id,
                            'attempt_number': attempt_number})

                # add question attempt urls to rendered_list question_data
                for (ind,q) in enumerate(rendered_list):
                    q["question_data"]["attempt_url"] = reverse(
                        'micourses:question_attempts', 
                        kwargs={'course_code': course.code, 
                                'content_id': self.thread_content.id, 
                                'attempt_number': attempt_number, 
                                'question_number': ind+1} )



        from mitesting.utils import round_and_int
        if self.thread_content:
            context['thread_content_points'] = round_and_int(
                self.thread_content.points)
        if self.current_attempt is None or self.current_attempt.score is None:
            context['attempt_score']=0
        else:
            context['attempt_score']=round_and_int(
                self.current_attempt.score,1)
        
        if self.current_attempt is None or \
           self.current_attempt.record.score is None:
            context['content_score']=0
        else:
            context['content_score']=round_and_int(
                self.current_attempt.record.score,1)


        # get list of the question numbers in assessment
        # if instructor or designer in course
        # if also staff, include links to admin pages
        if user_can_administer_assessment(self.request.user, course=course):
            question_numbers=[]
            if self.request.user.is_staff:
                context['assessment_admin_link'] = mark_safe(
                    "<p><a href='%s'>%s</a></p>" % (
                        reverse('admin:micourses_assessment_change',
                                args=(self.assessment.id,)),
                        'Admin link'))
            for q in rendered_list:
                # if staff, add link to admin page for quesiton
                if self.request.user.is_staff:
                    question_numbers.append(
                        "<a href='%s'>%s</a>" % (
                            reverse('admin:mitesting_question_change',
                                    args=(q['question'].id,)),
                            q['question'].id)
                    )
                else:
                    question_numbers.append(str(q['question'].id))
            question_numbers = ", ".join(question_numbers)
            question_numbers = mark_safe(question_numbers)
        else:
            question_numbers=None
        context['question_numbers']=question_numbers

        # turn off Google analytics for localhost/development site
        context['noanalytics']=(settings.SITE_ID <= 2)

        from mitesting.utils import get_new_seed
        context['new_seed']=get_new_seed(rng)

        return context