def test_course_page(self): """ Check out a course front-page """ _, c = create_offering() client = Client() # not logged in: should be redirected to login page response = client.get(c.get_absolute_url()) self.assertEqual(response.status_code, 302) # log in as student "0aaa0" client.login_user("0aaa0") p = Person.objects.get(userid="0aaa0") # not in the course: should get 403 Forbidden response = client.get(c.get_absolute_url()) self.assertEqual(response.status_code, 403) # add to course and try again m = Member(person=p, offering=c, role="STUD", credits=3, career="UGRD", added_reason="UNK") m.save() response = client.get(c.get_absolute_url()) self.assertEqual(response.status_code, 200) validate_content(self, response.content, c.get_absolute_url()) # dropped students should be forbidden m.role="DROP" m.save() response = client.get(c.get_absolute_url()) self.assertEqual(response.status_code, 403)
def test_course_page(self): """ Check out a course front-page """ _, c = create_offering() client = Client() # not logged in: should be redirected to login page response = client.get(c.get_absolute_url()) self.assertEqual(response.status_code, 302) # log in as student "0aaa0" client.login_user("0aaa0") p = Person.objects.get(userid="0aaa0") # not in the course: should get 403 Forbidden response = client.get(c.get_absolute_url()) self.assertEqual(response.status_code, 403) # add to course and try again m = Member(person=p, offering=c, role="STUD", credits=3, career="UGRD", added_reason="UNK") m.save() response = client.get(c.get_absolute_url()) self.assertEqual(response.status_code, 200) validate_content(self, response.content, c.get_absolute_url()) # dropped students should be forbidden m.role="DROP" m.save() response = client.get(c.get_absolute_url()) self.assertEqual(response.status_code, 403)
def test_select_components(self): """ Test submission component classes: subclasses, selection, sorting. """ _, course = create_offering() a1 = NumericActivity(name="Assignment 1", short_name="A1", status="RLS", offering=course, position=2, max_grade=15, due_date="2010-04-01") a1.save() a2 = NumericActivity(name="Assignment 2", short_name="A2", status="RLS", offering=course, position=1, max_grade=15, due_date="2010-03-01") a2.save() p = Person.objects.get(userid="ggbaker") member = Member(person=p, offering=course, role="INST", career="NONS", added_reason="UNK") member.save() c1 = URL.Component(activity=a1, title="URL Link", position=8) c1.save() c2 = Archive.Component(activity=a1, title="Archive File", position=1, max_size=100000) c2.save() c3 = Code.Component(activity=a1, title="Code File", position=3, max_size=2000, allowed=".py") c3.save() comps = select_all_components(a1) self.assertEqual(len(comps), 3) self.assertEqual(comps[0].title, 'Archive File') # make sure position=1 is first self.assertEqual(str(comps[1].Type), "submission.models.code.Code") self.assertEqual(str(comps[2].Type), "submission.models.url.URL")
def test_calc_letter(self): """ Test calculated letter functionality """ s, c = create_offering() na = NumericActivity(name="Assignment 1", short_name="A1", status="RLS", offering=c, position=2, max_grade=15, percent=10, group=False) na.save() a = CalLetterActivity(offering=c, name="A1 Letter", short_name="A1L", status="RLS", numeric_activity=na, exam_activity=None, position=3) a.save() # test cutoff getter/setter cs = a.get_cutoffs() cs[1] = decimal.Decimal('271') / decimal.Decimal('3') a.set_cutoffs(cs) s.save() cs = a.get_cutoffs() self.assertAlmostEqual(float(cs[1]), 90.333333333333)
def test_sort_letter(self): """ Test sorting letter grades """ s, c = create_offering() a = LetterActivity(name="Assignment 1", short_name="A1", status="RLS", offering=c, position=2, due_date=None, group=False) a.save() ms = [] for i in range(10): p = Person.objects.get(userid="0aaa%i"%i) m = Member(person=p, offering=c, role="STUD", added_reason="UNK") m.save() ms.append(m) g = LetterGrade(activity=a, member=ms[0], letter_grade="B+", flag="GRAD") g.save(entered_by='ggbaker') g = LetterGrade(activity=a, member=ms[1], letter_grade="A", flag="GRAD") g.save(entered_by='ggbaker') g = LetterGrade(activity=a, member=ms[2], letter_grade="D", flag="GRAD") g.save(entered_by='ggbaker') g = LetterGrade(activity=a, member=ms[3], letter_grade="B-", flag="GRAD") g.save(entered_by='ggbaker') g = LetterGrade(activity=a, member=ms[4], letter_grade="P", flag="GRAD") g.save(entered_by='ggbaker') g = LetterGrade(activity=a, member=ms[5], letter_grade="GN", flag="GRAD") g.save(entered_by='ggbaker') g = LetterGrade(activity=a, member=ms[6], letter_grade="F", flag="GRAD") g.save(entered_by='ggbaker') g = LetterGrade(activity=a, member=ms[7], letter_grade="DE", flag="GRAD") g.save(entered_by='ggbaker') g = LetterGrade(activity=a, member=ms[8], letter_grade="C-", flag="GRAD") g.save(entered_by='ggbaker') g = LetterGrade(activity=a, member=ms[9], letter_grade="N", flag="GRAD") g.save(entered_by='ggbaker') g_objs = LetterGrade.objects.filter(activity=a) gs = [g.letter_grade for g in g_objs] gs_sort = sorted_letters(gs) self.assertEquals(gs_sort, ['A', 'B+', 'B-', 'C-', 'D', 'P', 'F', 'DE', 'N', 'GN']) # pre-sort by userid for median testing (so we know which subsets we're grabbing) gs = [(int(g.member.person.userid[4:]), g.letter_grade) for g in g_objs] gs.sort() gs = [g for u,g in gs] # odd-length case self.assertEquals(median_letters(sorted_letters(gs[0:5])), "B-") # even length with median at boundary self.assertEquals(median_letters(sorted_letters(gs[0:6])), "B-/D") # empty list self.assertEquals(median_letters([]), u"\u2014")
def test_sort_letter(self): """ Test sorting letter grades """ s, c = create_offering() a = LetterActivity(name="Assignment 1", short_name="A1", status="RLS", offering=c, position=2, due_date=None, group=False) a.save() ms = [] for i in range(10): p = Person.objects.get(userid="0aaa%i"%i) m = Member(person=p, offering=c, role="STUD", added_reason="UNK") m.save() ms.append(m) g = LetterGrade(activity=a, member=ms[0], letter_grade="B+", flag="GRAD") g.save(entered_by='ggbaker') g = LetterGrade(activity=a, member=ms[1], letter_grade="A", flag="GRAD") g.save(entered_by='ggbaker') g = LetterGrade(activity=a, member=ms[2], letter_grade="D", flag="GRAD") g.save(entered_by='ggbaker') g = LetterGrade(activity=a, member=ms[3], letter_grade="B-", flag="GRAD") g.save(entered_by='ggbaker') g = LetterGrade(activity=a, member=ms[4], letter_grade="P", flag="GRAD") g.save(entered_by='ggbaker') g = LetterGrade(activity=a, member=ms[5], letter_grade="GN", flag="GRAD") g.save(entered_by='ggbaker') g = LetterGrade(activity=a, member=ms[6], letter_grade="F", flag="GRAD") g.save(entered_by='ggbaker') g = LetterGrade(activity=a, member=ms[7], letter_grade="DE", flag="GRAD") g.save(entered_by='ggbaker') g = LetterGrade(activity=a, member=ms[8], letter_grade="C-", flag="GRAD") g.save(entered_by='ggbaker') g = LetterGrade(activity=a, member=ms[9], letter_grade="N", flag="GRAD") g.save(entered_by='ggbaker') g_objs = LetterGrade.objects.filter(activity=a) gs = [g.letter_grade for g in g_objs] gs_sort = sorted_letters(gs) self.assertEqual(gs_sort, ['A', 'B+', 'B-', 'C-', 'D', 'P', 'F', 'DE', 'N', 'GN']) # pre-sort by userid for median testing (so we know which subsets we're grabbing) gs = [(int(g.member.person.userid[4:]), g.letter_grade) for g in g_objs] gs.sort() gs = [g for u,g in gs] # odd-length case self.assertEqual(median_letters(sorted_letters(gs[0:5])), "B-") # even length with median at boundary self.assertEqual(median_letters(sorted_letters(gs[0:6])), "B-/D") # empty list self.assertEqual(median_letters([]), "\u2014")
def test_group_submission_view(self): """ test if group submission can be viewed by group member and non group member """ now = datetime.datetime.now() _, course = create_offering() a1 = NumericActivity(name="Assignment 1", short_name="A1", status="RLS", offering=course, position=2, max_grade=15, due_date=now, group=True) a1.save() a2 = NumericActivity(name="Assignment 2", short_name="A2", status="RLS", offering=course, position=1, max_grade=15, due_date=now, group=True) a2.save() p = Person.objects.get(userid="ggbaker") member = Member(person=p, offering=course, role="INST", career="NONS", added_reason="UNK") member.save() c1 = URL.Component(activity=a1, title="URL Link", position=8) c1.save() c2 = Archive.Component(activity=a1, title="Archive File", position=1, max_size=100000) c2.save() c3 = Code.Component(activity=a1, title="Code File", position=3, max_size=2000, allowed=".py") c3.save() userid1 = "0aaa0" userid2 = "0aaa1" userid3 = "0aaa2" for u in [userid1, userid2,userid3]: p = Person.objects.get(userid=u) m = Member(person=p, offering=course, role="STUD", credits=3, career="UGRD", added_reason="UNK") m.save() m = Member.objects.get(person__userid=userid1, offering=course) g = Group(name="Test Group", manager=m, courseoffering=course) g.save() gm = GroupMember(group=g, student=m, confirmed=True, activity=a1) gm.save() gm = GroupMember(group=g, student=m, confirmed=True, activity=a2) gm.save() m = Member.objects.get(person__userid=userid2, offering=course) gm = GroupMember(group=g, student=m, confirmed=True, activity=a1) gm.save() gm = GroupMember(group=g, student=m, confirmed=True, activity=a2) gm.save() m = Member.objects.get(person__userid=userid3, offering=course) gm = GroupMember(group=g, student=m, confirmed=True, activity=a2) gm.save() client = Client() # login as "0aaa0", member of group : test_group for assignment1 and assgnment2 client.login_user("0aaa0") #submission page for assignment 1 url = reverse('submission.views.show_components', kwargs={'course_slug': course.slug,'activity_slug':a1.slug}) response = basic_page_tests(self, client, url) self.assertContains(response, "This is a group submission. You will submit on behalf of the group Test Group.") self.assertContains(response, "You haven't made a submission for this component.")
def test_upload(self): _, course = create_offering() a1 = NumericActivity(name="Assignment 1", short_name="A1", status="RLS", offering=course, position=2, max_grade=15, due_date=datetime.datetime.now() + datetime.timedelta(hours=1), group=False) a1.save() p = Person.objects.get(userid="ggbaker") member = Member(person=p, offering=course, role="INST", career="NONS", added_reason="UNK") member.save() c = Code.Component(activity=a1, title="Code File", position=3, max_size=2000, allowed=".py") c.save() userid1 = "0aaa0" userid2 = "0aaa1" userid3 = "0aaa2" for u in [userid1, userid2,userid3]: p = Person.objects.get(userid=u) m = Member(person=p, offering=course, role="STUD", credits=3, career="UGRD", added_reason="UNK") m.save() # submit as student client = Client() client.login_user("0aaa0") url = reverse('submission.views.show_components', kwargs={'course_slug': course.slug,'activity_slug':a1.slug}) response = basic_page_tests(self, client, url) # submit a file tmpf = tempfile.NamedTemporaryFile(suffix=".py", delete=False) codecontents = 'print "Hello World!"\n' tmpf.write(codecontents) tmpf.close() try: fh = open(tmpf.name, "r") data = {"%i-code" % (c.id): fh} response = client.post(url, data) self.assertEquals(response.status_code, 302) finally: os.unlink(tmpf.name) # make sure it's there and correct subs = StudentSubmission.objects.all() self.assertEquals(len(subs), 1) sub = subs[0] self.assertEquals(sub.member.person.userid, '0aaa0') codes = SubmittedCode.objects.all() self.assertEquals(len(codes), 1) code = codes[0] code.code.open() self.assertEquals(code.code.read(), codecontents)
def test_select_components(self): """ Test submission component classes: subclasses, selection, sorting. """ _, course = create_offering() a1 = NumericActivity(name="Assignment 1", short_name="A1", status="RLS", offering=course, position=2, max_grade=15, due_date="2010-04-01") a1.save() a2 = NumericActivity(name="Assignment 2", short_name="A2", status="RLS", offering=course, position=1, max_grade=15, due_date="2010-03-01") a2.save() p = Person.objects.get(userid="ggbaker") member = Member(person=p, offering=course, role="INST", career="NONS", added_reason="UNK") member.save() c1 = URL.Component(activity=a1, title="URL Link", position=8) c1.save() c2 = Archive.Component(activity=a1, title="Archive File", position=1, max_size=100000) c2.save() c3 = Code.Component(activity=a1, title="Code File", position=3, max_size=2000, allowed=".py") c3.save() comps = select_all_components(a1) self.assertEqual(len(comps), 3) self.assertEqual(comps[0].title, 'Archive File') # make sure position=1 is first self.assertEqual(str(comps[1].Type), "submission.models.code.Code") self.assertEqual(str(comps[2].Type), "submission.models.url.URL")
def test_activity_status(self): """ Test operations on activity's status """ # check the get_status_display override now = datetime.datetime.now() s, c = create_offering() a = NumericActivity(offering=c, name="Assign 1", short_name="A1", status="INVI", max_grade=10) self.assertEqual(a.get_status_display(), ACTIVITY_STATUS["INVI"]) a.status="RLS" self.assertEqual(a.get_status_display(), ACTIVITY_STATUS["RLS"]) a.status="URLS" self.assertEqual(a.get_status_display(), ACTIVITY_STATUS["URLS"]) a.due_date = now - datetime.timedelta(hours=1) self.assertEqual(a.get_status_display(), ACTIVITY_STATUS["URLS"]) # the special case: unreleased, before the due date a.due_date = now + datetime.timedelta(hours=1) self.assertEqual(a.get_status_display(), "no grades: due date not passed")
def test_calc_letter(self): """ Test calculated letter functionality """ s, c = create_offering() na = NumericActivity(name="Assignment 1", short_name="A1", status="RLS", offering=c, position=2, max_grade=15, percent=10, group=False) na.save() a = CalLetterActivity(offering=c, name="A1 Letter", short_name="A1L", status="RLS", numeric_activity=na, exam_activity=None, position=3) a.save() # test cutoff getter/setter cs = a.get_cutoffs() cs[1] = decimal.Decimal('271') / decimal.Decimal('3') a.set_cutoffs(cs) s.save() cs = a.get_cutoffs() self.assertAlmostEquals(float(cs[1]), 90.333333333333)
def test_activity_pages(self): """ Test pages around activities """ s, c = create_offering() # add some assignments and members a = NumericActivity(name="Assignment 1", short_name="A1", status="RLS", offering=c, position=2, max_grade=15, percent=10) a.save() a1=a a = NumericActivity(name="Assignment 2", short_name="A2", status="URLS", offering=c, position=6, max_grade=20, group=True) a.save() p = Person.objects.get(userid="ggbaker") m = Member(person=p, offering=c, role="INST", added_reason="UNK") m.save() p = Person.objects.get(userid="0aaa0") m = Member(person=p, offering=c, role="STUD", added_reason="UNK") m.save() # test instructor pages client = Client() client.login_user("ggbaker") response = basic_page_tests(self, client, '/' + c.slug + '/') self.assertContains(response, 'href="' + reverse('offering:groups:groupmanage', kwargs={'course_slug':c.slug}) +'"') basic_page_tests(self, client, c.get_absolute_url()) basic_page_tests(self, client, reverse('offering:student_info', kwargs={'course_slug': c.slug, 'userid': '0aaa0'})) basic_page_tests(self, client, reverse('offering:add_numeric_activity', kwargs={'course_slug':c.slug})) basic_page_tests(self, client, reverse('offering:add_letter_activity', kwargs={'course_slug':c.slug})) # test student pages client = Client() client.login_user("0aaa0") response = basic_page_tests(self, client, '/' + c.slug + '/') self.assertContains(response, "Gregorʏ (Greg) Baker") self.assertContains(response, 'href="' + reverse('offering:groups:groupmanage', kwargs={'course_slug':c.slug}) +'"') response = basic_page_tests(self, client, a.get_absolute_url()) # small class (one student) shouldn't contain summary stats self.assertNotContains(response, "Histogram") self.assertNotContains(response, "Standard Deviation")
def test_activity_pages(self): """ Test pages around activities """ s, c = create_offering() # add some assignments and members a = NumericActivity(name="Assignment 1", short_name="A1", status="RLS", offering=c, position=2, max_grade=15, percent=10) a.save() a1=a a = NumericActivity(name="Assignment 2", short_name="A2", status="URLS", offering=c, position=6, max_grade=20, group=True) a.save() p = Person.objects.get(userid="ggbaker") m = Member(person=p, offering=c, role="INST", added_reason="UNK") m.save() p = Person.objects.get(userid="0aaa0") m = Member(person=p, offering=c, role="STUD", added_reason="UNK") m.save() # test instructor pages client = Client() client.login_user("ggbaker") response = basic_page_tests(self, client, '/' + c.slug + '/') self.assertContains(response, 'href="' + reverse('groups.views.groupmanage', kwargs={'course_slug':c.slug}) +'"') basic_page_tests(self, client, c.get_absolute_url()) basic_page_tests(self, client, reverse('grades.views.student_info', kwargs={'course_slug': c.slug, 'userid': '0aaa0'})) basic_page_tests(self, client, reverse('grades.views.add_numeric_activity', kwargs={'course_slug':c.slug})) basic_page_tests(self, client, reverse('grades.views.add_letter_activity', kwargs={'course_slug':c.slug})) # test student pages client = Client() client.login_user("0aaa0") response = basic_page_tests(self, client, '/' + c.slug + '/') self.assertContains(response, "Gregory Baker") self.assertContains(response, 'href="' + reverse('groups.views.groupmanage', kwargs={'course_slug':c.slug}) +'"') response = basic_page_tests(self, client, a.get_absolute_url()) # small class (one student) shouldn't contain summary stats self.assertNotContains(response, "Histogram") self.assertNotContains(response, "Standard Deviation")
def test_activities(self): """ Test activity classes: subclasses, selection, sorting. """ s, c = create_offering() a = NumericActivity(name="Assignment 1", short_name="A1", status="RLS", offering=c, position=2, max_grade=15) a.save() a = NumericActivity(name="Assignment 2", short_name="A2", status="RLS", offering=c, position=6, max_grade=15) a.save() a = LetterActivity(name="Project", short_name="Proj", status="URLS", offering=c, position=1) a.save() a = CalNumericActivity(name="Total", short_name="Total", status="URLS", offering=c, position=42, max_grade=30, formula="[A1]+[A2]") a.save() allact = all_activities_filter(offering=c) self.assertEqual(len(allact), 4) self.assertEqual(allact[0].slug, 'proj') # make sure position=1 is first self.assertEqual(type(allact[1]), NumericActivity) self.assertEqual(type(allact[3]), CalNumericActivity)
def test_activities(self): """ Test activity classes: subclasses, selection, sorting. """ s, c = create_offering() a = NumericActivity(name="Assignment 1", short_name="A1", status="RLS", offering=c, position=2, max_grade=15) a.save() a = NumericActivity(name="Assignment 2", short_name="A2", status="RLS", offering=c, position=6, max_grade=15) a.save() a = LetterActivity(name="Project", short_name="Proj", status="URLS", offering=c, position=1) a.save() a = CalNumericActivity(name="Total", short_name="Total", status="URLS", offering=c, position=42, max_grade=30, formula="[A1]+[A2]") a.save() allact = all_activities_filter(offering=c) self.assertEqual(len(allact), 4) self.assertEqual(allact[0].slug, 'proj') # make sure position=1 is first self.assertEqual(type(allact[1]), NumericActivity) self.assertEqual(type(allact[3]), CalNumericActivity)
def test_component_view_page(self): _, course = create_offering() a1 = NumericActivity(name="Assignment 1", short_name="A1", status="RLS", offering=course, position=2, max_grade=15, due_date="2010-04-01") a1.save() a2 = NumericActivity(name="Assignment 2", short_name="A2", status="RLS", offering=course, position=1, max_grade=15, due_date="2010-03-01") a2.save() p = Person.objects.get(userid="ggbaker") member = Member(person=p, offering=course, role="INST", career="NONS", added_reason="UNK") member.save() c1 = URL.Component(activity=a1, title="URL Link", position=8) c1.save() c2 = Archive.Component(activity=a1, title="Archive File", position=1, max_size=100000) c2.save() c3 = Code.Component(activity=a1, title="Code File", position=3, max_size=2000, allowed=".py") c3.save() client = Client() client.login_user("ggbaker") # When no component, should display error message url = reverse('submission.views.show_components', kwargs={'course_slug':course.slug, 'activity_slug':a2.slug}) response = basic_page_tests(self, client, url) self.assertContains(response, 'No components configured.') # add component and test component = URL.Component(activity=a2, title="URL2", position=1) component.save() component = Archive.Component(activity=a2, title="Archive2", position=1, max_size=100) component.save() # should all appear response = basic_page_tests(self, client, url) self.assertContains(response, "URL2") self.assertContains(response, "Archive2") # make sure type displays #self.assertContains(response, '<li class="view"><label>Type:</label>Archive</li>') # delete component self.assertRaises(NotImplementedError, component.delete)
def test_instructor_workflow(self): """ Work through the site as an instructor """ s, c = create_offering() userid1 = "0aaa0" userid2 = "0aaa1" userid3 = "0aaa2" userid4 = "ggbaker" for u in [userid1, userid2, userid3, userid4]: p = Person.objects.get(userid=u) m = Member(person=p, offering=c, role="STUD", credits=3, career="UGRD", added_reason="UNK") m.save() m.role="INST" m.save() client = Client() client.login_user("ggbaker") # course main screen url = reverse('grades.views.course_info', kwargs={'course_slug': c.slug}) response = basic_page_tests(self, client, url) url = reverse('grades.views.activity_choice', kwargs={'course_slug': c.slug}) self.assertContains(response, 'href="' + url +'"') url = reverse('grades.views.add_numeric_activity', kwargs={'course_slug': c.slug}) response = basic_page_tests(self, client, url) # add activity import datetime now = datetime.datetime.now() due = now + datetime.timedelta(days=7) response = client.post(url, {'name':'Assignment 1', 'short_name':'A1', 'status':'URLS', 'due_date_0':due.strftime('%Y-%m-%d'), 'due_date_1':due.strftime('%H:%M:%S'), 'percent': '10', 'group': '1', 'max_grade': 25, 'extend_group': 'None'}) self.assertEquals(response.status_code, 302) acts = NumericActivity.objects.filter(offering=c) self.assertEquals(len(acts), 1) a = acts[0] self.assertEquals(a.name, "Assignment 1") self.assertEquals(a.slug, "a1") self.assertEquals(a.max_grade, 25) self.assertEquals(a.group, False) self.assertEquals(a.deleted, False) # add calculated numeric activity url = reverse('grades.views.add_cal_numeric_activity', kwargs={'course_slug': c.slug}) response = basic_page_tests(self, client, url) response = client.post(url, {'name':'Total', 'short_name':'Total', 'status':'URLS', 'group': '1', 'max_grade': 30, 'formula': '[A1]+5'}) self.assertEquals(response.status_code, 302) acts = CalNumericActivity.objects.filter(offering=c) self.assertEquals(len(acts), 1) a = acts[0] self.assertEquals(a.slug, "total") self.assertEquals(a.max_grade, 30) self.assertEquals(a.group, False) self.assertEquals(a.deleted, False) self.assertEquals(a.formula, '[A1]+5') # formula tester url = reverse('grades.views.formula_tester', kwargs={'course_slug': c.slug}) response = basic_page_tests(self, client, url) response = client.get(url, {'formula': '[A1]+5', 'a1-status': 'RLS', 'a1-value': '6', 'total-status': 'URLS'}) self.assertContains(response, '<div id="formula_result">11.0</div>') validate_content(self, response.content, url)
def test_group_staff(self): """ Check out group pages for an instructor: go through the group-creation process from the instructor side. """ s, c = create_offering() a = NumericActivity(name="Assignment 1", short_name="A1", status="URLS", offering=c, position=3, max_grade=20, group=True) a.save() a = NumericActivity(name="Assignment 2", short_name="A2", status="URLS", offering=c, position=6, max_grade=20, group=True) a.save() userid1 = "0aaa6" userid2 = "0aaa0" userid3 = "0aaa1" userid4 = "ggbaker" for u in [userid1, userid2, userid3, userid4]: p = Person.objects.get(userid=u) m = Member(person=p, offering=c, role="STUD", credits=3, career="UGRD", added_reason="UNK") m.save() m.role = "INST" m.save() client = Client() client.login_user("ggbaker") # group management screen url = reverse('offering:groups:groupmanage', kwargs={'course_slug': c.slug}) response = basic_page_tests(self, client, url) self.assertContains(response, "There are currently no groups in this course") url = reverse('offering:groups:create', kwargs={'course_slug': c.slug}) self.assertContains(response, 'href="%s"' % (url)) # group creation form response = basic_page_tests(self, client, url) # submit group create url = reverse('offering:groups:submit', kwargs={'course_slug': c.slug}) response = client.post( url, { "GroupName": "Test Group", "a1-selected": True, "a2-selected": False, '0aaa6-selected': False, '0aaa0-selected': True, '0aaa1-selected': True }) self.assertEqual(response.status_code, 302) gs = Group.objects.filter(courseoffering=c) self.assertEqual(len(gs), 1) self.assertEqual(gs[0].name, "Test Group") self.assertEqual(gs[0].slug, "g-test-group") gms = GroupMember.objects.filter(group__courseoffering=c, group=gs[0]) self.assertEqual(len(gms), 2) self.assertEqual(gms[0].confirmed, True) self.assertEqual(gms[1].confirmed, True) self.assertEqual(set(gm.student.person.userid for gm in gms), set([userid2, userid3])) # check group management screen again url = reverse('offering:groups:groupmanage', kwargs={'course_slug': c.slug}) response = basic_page_tests(self, client, url) # add membership form url = reverse('offering:groups:assign_student', kwargs={ 'course_slug': c.slug, 'group_slug': "g-test-group" }) response = basic_page_tests(self, client, url) # submit add membership response = client.post( url, { "a1-selected": True, "a2-selected": True, '0aaa6-selected': False, '0aaa0-selected': False, '0aaa1-selected': True }) self.assertEqual(response.status_code, 302) # both still in for A1 gms = GroupMember.objects.filter(group__courseoffering=c, group=gs[0], activity__slug="a1") self.assertEqual(set(gm.student.person.userid for gm in gms), set([userid2, userid3])) # 0aaa1 added for A2 gms = GroupMember.objects.filter(group__courseoffering=c, group=gs[0], activity__slug="a2") self.assertEqual(set(gm.student.person.userid for gm in gms), set([userid3])) # remove member form url = reverse('offering:groups:remove_student', kwargs={ 'course_slug': c.slug, 'group_slug': "g-test-group" }) response = basic_page_tests(self, client, url) # submit remove member response = client.post( url, { '0aaa6_a1-selected': True, '0aaa0_a1-selected': False, '0aaa1_a1-selected': True }) self.assertEqual(response.status_code, 302) # 0aaa1 gone for A1 gms = GroupMember.objects.filter(group__courseoffering=c, group=gs[0], activity__slug="a1") self.assertEqual(set(gm.student.person.userid for gm in gms), set([userid2])) # 0aaa1 still there for A2 gms = GroupMember.objects.filter(group__courseoffering=c, group=gs[0], activity__slug="a2") self.assertEqual(set(gm.student.person.userid for gm in gms), set([userid3])) # rename group form url = reverse('offering:groups:change_name', kwargs={ 'course_slug': c.slug, 'group_slug': "g-test-group" }) response = basic_page_tests(self, client, url) # submit change name response = client.post(url, {'name': 'otherName'}) self.assertEqual(response.status_code, 302) g = Group.objects.get(courseoffering=c) self.assertEqual(g.name, 'otherName') self.assertEqual(g.slug, 'g-test-group') # recheck basic view with more data url = reverse('offering:groups:groupmanage', kwargs={'course_slug': c.slug}) response = basic_page_tests(self, client, url) url = reverse('offering:groups:view_group', kwargs={ 'course_slug': c.slug, 'group_slug': "g-test-group" }) response = basic_page_tests(self, client, url)
def test_group_models(self): """ Test the backend for groups """ s, c = create_offering() a = NumericActivity(name="Assignment 1", short_name="A1", status="URLS", offering=c, position=3, max_grade=20, group=True) a.save() a1 = a a = NumericActivity(name="Assignment 2", short_name="A2", status="URLS", offering=c, position=6, max_grade=20, group=True) a.save() a2 = a userid1 = "0aaa4" userid2 = "0aaa0" userid3 = "0aaa1" userid4 = "0aaa2" for u in [userid1, userid2, userid3, userid4]: p = Person.objects.get(userid=u) m = Member(person=p, offering=c, role="STUD", credits=3, career="UGRD", added_reason="UNK") m.save() # basics m = Member.objects.get(person__userid=userid1, offering=c) g = Group(name="Test Group", manager=m, courseoffering=c) g.save() self.assertEqual(g.slug, 'g-test-group') gm = GroupMember(group=g, student=m, confirmed=True, activity=a1) gm.save() m = Member.objects.get(person__userid=userid2, offering=c) gm = GroupMember(group=g, student=m, confirmed=True, activity=a1) gm.save() gs = Group.objects.filter(courseoffering=c) self.assertEqual(len(gs), 1) g = gs[0] self.assertEqual( set([gm.student.person.userid for gm in g.groupmember_set.all()]), set([userid1, userid2])) # check uniqueness of activity + member m = Member.objects.get(person__userid=userid3, offering=c) g2 = Group(name="Other Group", manager=m, courseoffering=c) g2.save() gm = GroupMember(group=g2, student=m, confirmed=True, activity=a1) gm.save() gm = GroupMember(group=g, student=m, confirmed=True, activity=a1) # south doesn't seem to create the constraints in SQLite for testing #self.assertRaises(IntegrityError, gm.save) # uniqueness of group name g3 = Group(name="Other Group", manager=m, courseoffering=c) # south doesn't seem to create the constraints in SQLite for testing #self.assertRaises(IntegrityError, g3.save) # finding all activities this group covers members = GroupMember.objects.filter(group=g) all_act = all_activities(members) self.assertEqual(set(a.slug for a in all_act), set([a1.slug])) # add a member for assignment 2 and check again gm = GroupMember(group=g, student=m, confirmed=True, activity=a2) gm.save() members = GroupMember.objects.filter(group=g) all_act = all_activities(members) self.assertEqual(set(a.slug for a in all_act), set([a1.slug, a2.slug])) # check student-editable tests # test dates m = Member.objects.get(offering=c, person__userid="0aaa0") gm = GroupMember.objects.get(group=g, student=m, activity=a1) a1.due_date = datetime.datetime.now() - datetime.timedelta( days=1) # yesterday a1.save() self.assertTrue("passed" in gm.student_editable("0aaa0")) a1.due_date = datetime.datetime.now() + datetime.timedelta( days=1) # tomorrow a1.save() gm = GroupMember.objects.get(group=g, student=m, activity=a1) self.assertEqual(gm.student_editable("0aaa0"), '') # not member for this activity self.assertTrue("not a member" in gm.student_editable("0aaa1")) # already graded gr = NumericGrade(activity=a1, member=m, value=1, flag="GRAD") gr.save(entered_by='ggbaker') self.assertTrue("grade" in gm.student_editable("0aaa0")) gr.flag = "NOGR" gr.save(entered_by='ggbaker') self.assertEqual(gm.student_editable("0aaa0"), '') # submission made s = GroupSubmission(group=g, creator=m, activity=a1) s.save() self.assertTrue("submission" in gm.student_editable("0aaa0"))
def test_group_student(self): """ Check out group pages for student: go through the whole group-creation process from the student side. """ s, c = create_offering() a = NumericActivity(name="Assignment 1", short_name="A1", status="URLS", offering=c, position=3, max_grade=20, group=True) a.save() a1 = a a = NumericActivity(name="Assignment 2", short_name="A2", status="URLS", offering=c, position=6, max_grade=20, group=True) a.save() userid1 = "0aaa6" userid2 = "0aaa0" userid3 = "0aaa1" userid4 = "0aaa2" for u in [userid1, userid2, userid3, userid4]: p = Person.objects.get(userid=u) m = Member(person=p, offering=c, role="STUD", credits=3, career="UGRD", added_reason="UNK") m.save() client = Client() client.login_user(userid1) # group management screen url = reverse('offering:groups:groupmanage', kwargs={'course_slug': c.slug}) response = basic_page_tests(self, client, url) self.assertContains(response, "You don't belong to any group") url = reverse('offering:groups:create', kwargs={'course_slug': c.slug}) self.assertContains(response, 'href="%s"' % (url)) # group creation form response = basic_page_tests(self, client, url) # submit group create url = reverse('offering:groups:submit', kwargs={'course_slug': c.slug}) response = client.post(url, { "GroupName": "Test Group", "a1-selected": True, "a2-selected": False }) self.assertEqual(response.status_code, 302) gs = Group.objects.filter(courseoffering=c) self.assertEqual(len(gs), 1) self.assertEqual(gs[0].name, "Test Group") self.assertEqual(gs[0].manager.person.userid, userid1) gms = GroupMember.objects.filter(group__courseoffering=c) self.assertEqual(len(gms), 1) self.assertEqual(gms[0].student.person.userid, userid1) self.assertEqual(gms[0].confirmed, True) # member invite form url = reverse('offering:groups:invite', kwargs={ 'course_slug': c.slug, 'group_slug': 'g-test-group' }) response = basic_page_tests(self, client, url) # submit invite form: invite userid2 and userid3 response = client.post(url, {"name": userid2}) response = client.post(url, {"name": userid3}) self.assertEqual(response.status_code, 302) gms = GroupMember.objects.filter( group__courseoffering=c, student__person__userid__in=[userid2, userid3]) self.assertEqual(len(gms), 2) self.assertEqual(gms[0].confirmed, False) self.assertEqual(gms[1].confirmed, False) # log in as userid2 and confirm client.login_user(userid2) url = reverse('offering:groups:groupmanage', kwargs={'course_slug': c.slug}) response = basic_page_tests(self, client, url) self.assertContains(response, ", " + userid1) self.assertContains(response, ", " + userid2 + " (unconfirmed)") url = reverse('offering:groups:join', kwargs={ 'course_slug': c.slug, 'group_slug': 'g-test-group' }) response = client.post(url) self.assertEqual(response.status_code, 302) gms = GroupMember.objects.filter(group__courseoffering=c, student__person__userid=userid2) self.assertEqual(len(gms), 1) self.assertEqual(gms[0].confirmed, True) # log in as userid3 and reject client.login_user(userid3) url = reverse('offering:groups:reject', kwargs={ 'course_slug': c.slug, 'group_slug': 'g-test-group' }) response = client.post(url) self.assertEqual(response.status_code, 302) gms = GroupMember.objects.filter(group__courseoffering=c, student__person__userid=userid3) self.assertEqual(len(gms), 0) # inviting userid4 shouldn't work if already in a group m = Member.objects.get(person__userid=userid4, offering=c) g = Group(name="Other Group", manager=m, courseoffering=c) g.save() gm = GroupMember(group=g, student=m, confirmed=True, activity=a1) gm.save() client.login_user(userid1) url = reverse('offering:groups:invite', kwargs={ 'course_slug': c.slug, 'group_slug': 'g-test-group' }) response = client.post(url, {"name": userid4}) gms = GroupMember.objects.filter(group__courseoffering=c, student__person__userid=userid4) self.assertEqual(len(gms), 1) self.assertEqual(gms[0].group.slug, 'g-other-group')
def test_component_view_page(self): _, course = create_offering() a1 = NumericActivity(name="Assignment 1", short_name="A1", status="RLS", offering=course, position=2, max_grade=15, due_date="2010-04-01") a1.save() a2 = NumericActivity(name="Assignment 2", short_name="A2", status="RLS", offering=course, position=1, max_grade=15, due_date="2010-03-01") a2.save() p = Person.objects.get(userid="ggbaker") member = Member(person=p, offering=course, role="INST", career="NONS", added_reason="UNK") member.save() c1 = URL.Component(activity=a1, title="URL Link", position=8) c1.save() c2 = Archive.Component(activity=a1, title="Archive File", position=1, max_size=100000) c2.save() c3 = Code.Component(activity=a1, title="Code File", position=3, max_size=2000, allowed=".py") c3.save() client = Client() client.login_user("ggbaker") # When no component, should display error message url = reverse('offering:submission:show_components', kwargs={ 'course_slug': course.slug, 'activity_slug': a2.slug }) response = basic_page_tests(self, client, url) self.assertContains(response, 'No components configured.') # add component and test component = URL.Component(activity=a2, title="URL2", position=1) component.save() component = Archive.Component(activity=a2, title="Archive2", position=1, max_size=100) component.save() # should all appear response = basic_page_tests(self, client, url) self.assertContains(response, "URL2") self.assertContains(response, "Archive2") # make sure type displays #self.assertContains(response, '<li class="view"><label>Type:</label>Archive</li>') # delete component self.assertRaises(NotImplementedError, component.delete)
def test_group_models(self): """ Test the backend for groups """ s, c = create_offering() a = NumericActivity(name="Assignment 1", short_name="A1", status="URLS", offering=c, position=3, max_grade=20, group=True) a.save() a1 = a a = NumericActivity(name="Assignment 2", short_name="A2", status="URLS", offering=c, position=6, max_grade=20, group=True) a.save() a2 = a userid1 = "0aaa4" userid2 = "0aaa0" userid3 = "0aaa1" userid4 = "0aaa2" for u in [userid1, userid2, userid3, userid4]: p = Person.objects.get(userid=u) m = Member(person=p, offering=c, role="STUD", credits=3, career="UGRD", added_reason="UNK") m.save() # basics m = Member.objects.get(person__userid=userid1, offering=c) g = Group(name="Test Group", manager=m, courseoffering=c) g.save() self.assertEqual(g.slug, 'g-test-group') gm = GroupMember(group=g, student=m, confirmed=True, activity=a1) gm.save() m = Member.objects.get(person__userid=userid2, offering=c) gm = GroupMember(group=g, student=m, confirmed=True, activity=a1) gm.save() gs = Group.objects.filter(courseoffering=c) self.assertEqual(len(gs), 1) g = gs[0] self.assertEqual(set([gm.student.person.userid for gm in g.groupmember_set.all()]), set([userid1,userid2])) # check uniqueness of activity + member m = Member.objects.get(person__userid=userid3, offering=c) g2 = Group(name="Other Group", manager=m, courseoffering=c) g2.save() gm = GroupMember(group=g2, student=m, confirmed=True, activity=a1) gm.save() gm = GroupMember(group=g, student=m, confirmed=True, activity=a1) # south doesn't seem to create the constraints in SQLite for testing #self.assertRaises(IntegrityError, gm.save) # uniqueness of group name g3 = Group(name="Other Group", manager=m, courseoffering=c) # south doesn't seem to create the constraints in SQLite for testing #self.assertRaises(IntegrityError, g3.save) # finding all activities this group covers members = GroupMember.objects.filter(group=g) all_act = all_activities(members) self.assertEqual(set(a.slug for a in all_act), set([a1.slug])) # add a member for assignment 2 and check again gm = GroupMember(group=g, student=m, confirmed=True, activity=a2) gm.save() members = GroupMember.objects.filter(group=g) all_act = all_activities(members) self.assertEqual(set(a.slug for a in all_act), set([a1.slug, a2.slug])) # check student-editable tests # test dates m = Member.objects.get(offering=c, person__userid="0aaa0") gm = GroupMember.objects.get(group=g, student=m, activity=a1) a1.due_date = datetime.datetime.now() - datetime.timedelta(days=1) # yesterday a1.save() self.assertTrue("passed" in gm.student_editable("0aaa0")) a1.due_date = datetime.datetime.now() + datetime.timedelta(days=1) # tomorrow a1.save() gm = GroupMember.objects.get(group=g, student=m, activity=a1) self.assertEqual(gm.student_editable("0aaa0"), '') # not member for this activity self.assertTrue("not a member" in gm.student_editable("0aaa1")) # already graded gr = NumericGrade(activity=a1, member=m, value=1, flag="GRAD") gr.save(entered_by='ggbaker') self.assertTrue("grade" in gm.student_editable("0aaa0")) gr.flag="NOGR" gr.save(entered_by='ggbaker') self.assertEqual(gm.student_editable("0aaa0"), '') # submission made s = GroupSubmission(group=g, creator=m, activity=a1) s.save() self.assertTrue("submission" in gm.student_editable("0aaa0"))
def test_instructor_workflow(self): """ Work through the site as an instructor """ s, c = create_offering() userid1 = "0aaa0" userid2 = "0aaa1" userid3 = "0aaa2" userid4 = "ggbaker" for u in [userid1, userid2, userid3, userid4]: p = Person.objects.get(userid=u) m = Member(person=p, offering=c, role="STUD", credits=3, career="UGRD", added_reason="UNK") m.save() m.role = "INST" m.save() client = Client() client.login_user("ggbaker") # course main screen url = reverse('offering:course_info', kwargs={'course_slug': c.slug}) response = basic_page_tests(self, client, url) url = reverse('offering:activity_choice', kwargs={'course_slug': c.slug}) self.assertContains(response, 'href="' + url + '"') url = reverse('offering:add_numeric_activity', kwargs={'course_slug': c.slug}) response = basic_page_tests(self, client, url) # add activity import datetime now = datetime.datetime.now() due = now + datetime.timedelta(days=7) response = client.post( url, { 'name': 'Assignment 1', 'short_name': 'A1', 'status': 'URLS', 'due_date_0': due.strftime('%Y-%m-%d'), 'due_date_1': due.strftime('%H:%M:%S'), 'percent': '10', 'group': '1', 'max_grade': 25, 'extend_group': 'None' }) self.assertEqual(response.status_code, 302) acts = NumericActivity.objects.filter(offering=c) self.assertEqual(len(acts), 1) a = acts[0] self.assertEqual(a.name, "Assignment 1") self.assertEqual(a.slug, "a1") self.assertEqual(a.max_grade, 25) self.assertEqual(a.group, False) self.assertEqual(a.deleted, False) # add calculated numeric activity url = reverse('offering:add_cal_numeric_activity', kwargs={'course_slug': c.slug}) response = basic_page_tests(self, client, url) response = client.post( url, { 'name': 'Total', 'short_name': 'Total', 'status': 'URLS', 'group': '1', 'max_grade': 30, 'formula': '[A1]+5' }) self.assertEqual(response.status_code, 302) acts = CalNumericActivity.objects.filter(offering=c) self.assertEqual(len(acts), 1) a = acts[0] self.assertEqual(a.slug, "total") self.assertEqual(a.max_grade, 30) self.assertEqual(a.group, False) self.assertEqual(a.deleted, False) self.assertEqual(a.formula, '[A1]+5') # formula tester url = reverse('offering:formula_tester', kwargs={'course_slug': c.slug}) response = basic_page_tests(self, client, url) response = client.get( url, { 'formula': '[A1]+5', 'a1-status': 'RLS', 'a1-value': '6', 'total-status': 'URLS' }) self.assertContains(response, '<div id="formula_result">11.0</div>') validate_content(self, response.content, url)
def test_group_staff(self): """ Check out group pages for an instructor: go through the group-creation process from the instructor side. """ s, c = create_offering() a = NumericActivity(name="Assignment 1", short_name="A1", status="URLS", offering=c, position=3, max_grade=20, group=True) a.save() a = NumericActivity(name="Assignment 2", short_name="A2", status="URLS", offering=c, position=6, max_grade=20, group=True) a.save() userid1 = "0aaa6" userid2 = "0aaa0" userid3 = "0aaa1" userid4 = "ggbaker" for u in [userid1, userid2, userid3, userid4]: p = Person.objects.get(userid=u) m = Member(person=p, offering=c, role="STUD", credits=3, career="UGRD", added_reason="UNK") m.save() m.role="INST" m.save() client = Client() client.login_user("ggbaker") # group management screen url = reverse('groups.views.groupmanage', kwargs={'course_slug': c.slug}) response = basic_page_tests(self, client, url) self.assertContains(response, "There are currently no groups in this course") url = reverse('groups.views.create', kwargs={'course_slug': c.slug}) self.assertContains(response, 'href="%s"'%(url)) # group creation form response = basic_page_tests(self, client, url) # submit group create url = reverse('groups.views.submit', kwargs={'course_slug': c.slug}) response = client.post(url, {"GroupName": "Test Group", "a1-selected": True, "a2-selected": False, '0aaa6-selected': False, '0aaa0-selected': True, '0aaa1-selected': True}) self.assertEquals(response.status_code, 302) gs = Group.objects.filter(courseoffering=c) self.assertEquals(len(gs), 1) self.assertEquals(gs[0].name, "Test Group") self.assertEquals(gs[0].slug, "g-test-group") gms = GroupMember.objects.filter(group__courseoffering=c, group=gs[0]) self.assertEquals(len(gms), 2) self.assertEquals(gms[0].confirmed, True) self.assertEquals(gms[1].confirmed, True) self.assertEquals(set(gm.student.person.userid for gm in gms), set([userid2,userid3])) # check group management screen again url = reverse('groups.views.groupmanage', kwargs={'course_slug': c.slug}) response = basic_page_tests(self, client, url) # add membership form url = reverse('groups.views.assign_student', kwargs={'course_slug': c.slug, 'group_slug': "g-test-group"}) response = basic_page_tests(self, client, url) # submit add membership response = client.post(url, {"a1-selected": True, "a2-selected": True, '0aaa6-selected': False, '0aaa0-selected': False, '0aaa1-selected': True}) self.assertEquals(response.status_code, 302) # both still in for A1 gms = GroupMember.objects.filter(group__courseoffering=c, group=gs[0], activity__slug="a1") self.assertEquals(set(gm.student.person.userid for gm in gms), set([userid2,userid3])) # 0aaa1 added for A2 gms = GroupMember.objects.filter(group__courseoffering=c, group=gs[0], activity__slug="a2") self.assertEquals(set(gm.student.person.userid for gm in gms), set([userid3])) # remove member form url = reverse('groups.views.remove_student', kwargs={'course_slug': c.slug, 'group_slug': "g-test-group"}) response = basic_page_tests(self, client, url) # submit remove member response = client.post(url, {'0aaa6_a1-selected': True, '0aaa0_a1-selected': False, '0aaa1_a1-selected': True}) self.assertEquals(response.status_code, 302) # 0aaa1 gone for A1 gms = GroupMember.objects.filter(group__courseoffering=c, group=gs[0], activity__slug="a1") self.assertEquals(set(gm.student.person.userid for gm in gms), set([userid2])) # 0aaa1 still there for A2 gms = GroupMember.objects.filter(group__courseoffering=c, group=gs[0], activity__slug="a2") self.assertEquals(set(gm.student.person.userid for gm in gms), set([userid3])) # rename group form url = reverse('groups.views.change_name', kwargs={'course_slug': c.slug, 'group_slug': "g-test-group"}) response = basic_page_tests(self, client, url) # submit change name response = client.post(url, {'name': 'otherName'}) self.assertEquals(response.status_code, 302) g = Group.objects.get(courseoffering=c) self.assertEquals(g.name, 'otherName') self.assertEquals(g.slug, 'g-test-group') # recheck basic view with more data url = reverse('groups.views.groupmanage', kwargs={'course_slug': c.slug}) response = basic_page_tests(self, client, url) url = reverse('groups.views.view_group', kwargs={'course_slug': c.slug, 'group_slug': "g-test-group"}) response = basic_page_tests(self, client, url)
def test_formulas(self): """ Test the formula parsing & evaluation. """ # set up course and related data s, c = create_offering() p = Person.objects.get(userid="0aaa0") m = Member(person=p, offering=c, role="STUD", credits=3, added_reason="UNK") m.save() a = NumericActivity(name="Paragraph", short_name="\u00b6", status="RLS", offering=c, position=3, max_grade=40, percent=5) a.save() g = NumericGrade(activity=a, member=m, value="4.5", flag="CALC") g.save(entered_by='ggbaker') a1 = NumericActivity(name="Assignment #1", short_name="A1", status="RLS", offering=c, position=1, max_grade=15, percent=10) a1.save() g = NumericGrade(activity=a1, member=m, value=10, flag="GRAD") g.save(entered_by='ggbaker') a2 = NumericActivity(name="Assignment #2", short_name="A2", status="URLS", offering=c, position=2, max_grade=40, percent=20) a2.save(entered_by='ggbaker') g = NumericGrade(activity=a2, member=m, value=30, flag="GRAD") g.save(entered_by='ggbaker') ca = CalNumericActivity(name="Final Grade", short_name="FG", status="RLS", offering=c, position=4, max_grade=1) ca.save() activities = NumericActivity.objects.filter(offering=c) act_dict = activities_dictionary(activities) # make sure a formula can be pickled and unpickled safely (i.e. can be cached) tree = parse("sum([Assignment #1], [A1], [A2])/20*-3", c, ca) p = pickle.dumps(tree) tree2 = pickle.loads(p) self.assertEqual(tree, tree2) # check that it found the right list of columns used self.assertEqual(cols_used(tree), set(['A1', 'A2', 'Assignment #1'])) # test parsing and evaluation to make sure we get the right values out for expr, correct in test_formulas: tree = parse(expr, c, ca) res = eval_parse(tree, ca, act_dict, m, False) self.assertAlmostEqual(correct, res, msg="Incorrect result for %s" % (expr, )) # test some badly-formed stuff for appropriate exceptions tree = parse("1 + BEST(3, [A1], [A2])", c, ca) self.assertRaises(EvalException, eval_parse, tree, ca, act_dict, m, True) tree = parse("1 + BEST(0, [A1], [A2])", c, ca) self.assertRaises(EvalException, eval_parse, tree, ca, act_dict, m, True) tree = parse("[Foo] /2", c, ca) self.assertRaises(KeyError, eval_parse, tree, ca, act_dict, m, True) tree = parse("[a1] /2", c, ca) self.assertRaises(KeyError, eval_parse, tree, ca, act_dict, m, True) self.assertRaises(ParseException, parse, "AVG()", c, ca) self.assertRaises(ParseException, parse, "(2+3*84", c, ca) self.assertRaises(ParseException, parse, "2+3**84", c, ca) self.assertRaises(ParseException, parse, "AVG(2,3,4", c, ca) self.assertRaises(ParseException, parse, "{something}", c, ca) # test visible/invisible switching tree = parse("[Assignment #2]", c, ca) res = eval_parse(tree, ca, act_dict, m, True) self.assertAlmostEqual(res, 0.0) res = eval_parse(tree, ca, act_dict, m, False) self.assertAlmostEqual(res, 30.0) # test unreleased/missing grade conditions expr = "[Assignment #2]" tree = parse(expr, c, ca) # unreleased assignment (with grade) should not be included in the calculation a2.status = 'URLS' a2.save() activities = NumericActivity.objects.filter(offering=c) act_dict = activities_dictionary(activities) res = eval_parse(tree, ca, act_dict, m, True) self.assertAlmostEqual(res, 0.0) # ... unless the instructor said to do so. ca.set_calculation_leak(True) res = eval_parse(tree, ca, act_dict, m, True) self.assertAlmostEqual(res, 30.0) # explicit no grade (released assignment) g.flag = "NOGR" g.save(entered_by='ggbaker') a2.status = 'RLS' a2.save(entered_by='ggbaker') activities = NumericActivity.objects.filter(offering=c) act_dict = activities_dictionary(activities) res = eval_parse(tree, ca, act_dict, m, True) self.assertAlmostEqual(res, 0.0) # no grade in database (released assignment) g.delete() activities = NumericActivity.objects.filter(offering=c) act_dict = activities_dictionary(activities) res = eval_parse(tree, ca, act_dict, m, True) self.assertAlmostEqual(res, 0.0) # test [[activitytotal]] expr = "[[activitytotal]]" tree = parse(expr, c, ca) res = eval_parse(tree, ca, act_dict, m, True) self.assertAlmostEqual(res, 7.229166666)
def test_group_submission_view(self): """ test if group submission can be viewed by group member and non group member """ now = datetime.datetime.now() _, course = create_offering() a1 = NumericActivity(name="Assignment 1", short_name="A1", status="RLS", offering=course, position=2, max_grade=15, due_date=now, group=True) a1.save() a2 = NumericActivity(name="Assignment 2", short_name="A2", status="RLS", offering=course, position=1, max_grade=15, due_date=now, group=True) a2.save() p = Person.objects.get(userid="ggbaker") member = Member(person=p, offering=course, role="INST", career="NONS", added_reason="UNK") member.save() c1 = URL.Component(activity=a1, title="URL Link", position=8) c1.save() c2 = Archive.Component(activity=a1, title="Archive File", position=1, max_size=100000) c2.save() c3 = Code.Component(activity=a1, title="Code File", position=3, max_size=2000, allowed=".py") c3.save() userid1 = "0aaa0" userid2 = "0aaa1" userid3 = "0aaa2" for u in [userid1, userid2, userid3]: p = Person.objects.get(userid=u) m = Member(person=p, offering=course, role="STUD", credits=3, career="UGRD", added_reason="UNK") m.save() m = Member.objects.get(person__userid=userid1, offering=course) g = Group(name="Test Group", manager=m, courseoffering=course) g.save() gm = GroupMember(group=g, student=m, confirmed=True, activity=a1) gm.save() gm = GroupMember(group=g, student=m, confirmed=True, activity=a2) gm.save() m = Member.objects.get(person__userid=userid2, offering=course) gm = GroupMember(group=g, student=m, confirmed=True, activity=a1) gm.save() gm = GroupMember(group=g, student=m, confirmed=True, activity=a2) gm.save() m = Member.objects.get(person__userid=userid3, offering=course) gm = GroupMember(group=g, student=m, confirmed=True, activity=a2) gm.save() client = Client() # login as "0aaa0", member of group : test_group for assignment1 and assgnment2 client.login_user("0aaa0") #submission page for assignment 1 url = reverse('offering:submission:show_components', kwargs={ 'course_slug': course.slug, 'activity_slug': a1.slug }) response = basic_page_tests(self, client, url) self.assertContains( response, "This is a group activity. You will submit on behalf of the group “Test Group”." ) self.assertContains( response, "You haven't made a submission for this component.")
def test_group_change(self): """ Test changing group <-> individual on an activity. Should only be possible in some conditions. """ s, c = create_offering() # add some assignments and members due = datetime.datetime.now() + datetime.timedelta(days=1) due_date = str(due.date()) due_time = due.time().strftime("%H:%M:%S") a = NumericActivity(name="Assignment 1", short_name="A1", status="RLS", offering=c, position=2, max_grade=15, percent=10, due_date=due, group=False) a.save() p = Person.objects.get(userid="ggbaker") m = Member(person=p, offering=c, role="INST", added_reason="UNK") m.save() p = Person.objects.get(userid="0aaa0") m = Member(person=p, offering=c, role="STUD", added_reason="UNK") m.save() client = Client() client.login_user("ggbaker") url = reverse('grades.views.edit_activity', kwargs={'course_slug': c.slug, 'activity_slug': a.slug}) # for whatever reason, '0' is group and '1' is individual for the group value submit_dict = {'name': a.name, 'short_name': a.short_name, 'status': a.status, 'due_date_0': due_date, 'due_date_1': due_time, 'percent': a.percent, 'max_grade': a.max_grade, 'group': '1', 'extend_group': 'None'} # no change response = client.post(url, submit_dict) self.assertEquals(response.status_code, 302) # successful submit -> redirect self.assertEquals(NumericActivity.objects.get(id=a.id).group, False) # change indiv -> group submit_dict['group'] = '0' response = client.post(url, submit_dict) self.assertEquals(response.status_code, 302) self.assertEquals(NumericActivity.objects.get(id=a.id).group, True) # try with activity past due a.due_date = datetime.datetime.now() - datetime.timedelta(days=1) a.save() submit_dict['due_date_0'] = str(a.due_date.date()) submit_dict['group'] = '0' response = client.post(url, submit_dict) self.assertEquals(response.status_code, 200) # error on form -> 200 and back to form with error self.assertContains(response, "due date has passed") # try with a mark in the system a.due_date = datetime.datetime.now() + datetime.timedelta(days=1) a.save() submit_dict['due_date_0'] = str(a.due_date.date()) submit_dict['group'] = '0' g = NumericGrade(activity=a, member=m, value=2, flag="GRAD") g.save(entered_by='ggbaker') response = client.post(url, submit_dict) self.assertEquals(response.status_code, 200) self.assertContains(response, "grades have already been given") # try with a submission in the system g.flag = "NOGR" g.save(entered_by='ggbaker') s = StudentSubmission(activity=a, member=m) s.save() response = client.post(url, submit_dict) self.assertEquals(response.status_code, 200) self.assertContains(response, "submissions have already been made")
def test_upload(self): _, course = create_offering() a1 = NumericActivity(name="Assignment 1", short_name="A1", status="RLS", offering=course, position=2, max_grade=15, due_date=datetime.datetime.now() + datetime.timedelta(hours=1), group=False) a1.save() p = Person.objects.get(userid="ggbaker") member = Member(person=p, offering=course, role="INST", career="NONS", added_reason="UNK") member.save() c = Code.Component(activity=a1, title="Code File", position=3, max_size=2000, allowed=".py") c.save() userid1 = "0aaa0" userid2 = "0aaa1" userid3 = "0aaa2" for u in [userid1, userid2, userid3]: p = Person.objects.get(userid=u) m = Member(person=p, offering=course, role="STUD", credits=3, career="UGRD", added_reason="UNK") m.save() # submit as student client = Client() client.login_user("0aaa0") url = reverse('offering:submission:show_components', kwargs={ 'course_slug': course.slug, 'activity_slug': a1.slug }) response = basic_page_tests(self, client, url) # submit a file tmpf = tempfile.NamedTemporaryFile(suffix=".py", delete=False) codecontents = 'print "Hello World!"\n' tmpf.write(codecontents) tmpf.close() try: fh = open(tmpf.name, "r") data = {"%i-code" % (c.id): fh} response = client.post(url, data) self.assertEquals(response.status_code, 302) finally: os.unlink(tmpf.name) # make sure it's there and correct subs = StudentSubmission.objects.all() self.assertEquals(len(subs), 1) sub = subs[0] self.assertEquals(sub.member.person.userid, '0aaa0') codes = SubmittedCode.objects.all() self.assertEquals(len(codes), 1) code = codes[0] code.code.open() self.assertEquals(code.code.read(), codecontents)
def test_group_change(self): """ Test changing group <-> individual on an activity. Should only be possible in some conditions. """ s, c = create_offering() # add some assignments and members due = datetime.datetime.now() + datetime.timedelta(days=1) due_date = str(due.date()) due_time = due.time().strftime("%H:%M:%S") a = NumericActivity(name="Assignment 1", short_name="A1", status="RLS", offering=c, position=2, max_grade=15, percent=10, due_date=due, group=False) a.save() p = Person.objects.get(userid="ggbaker") m = Member(person=p, offering=c, role="INST", added_reason="UNK") m.save() p = Person.objects.get(userid="0aaa0") m = Member(person=p, offering=c, role="STUD", added_reason="UNK") m.save() client = Client() client.login_user("ggbaker") url = reverse('offering:edit_activity', kwargs={ 'course_slug': c.slug, 'activity_slug': a.slug }) # for whatever reason, '0' is group and '1' is individual for the group value submit_dict = { 'name': a.name, 'short_name': a.short_name, 'status': a.status, 'due_date_0': due_date, 'due_date_1': due_time, 'percent': a.percent, 'max_grade': a.max_grade, 'group': '1', 'extend_group': 'None' } # no change response = client.post(url, submit_dict) self.assertEqual(response.status_code, 302) # successful submit -> redirect self.assertEqual(NumericActivity.objects.get(id=a.id).group, False) # change indiv -> group submit_dict['group'] = '0' response = client.post(url, submit_dict) self.assertEqual(response.status_code, 302) self.assertEqual(NumericActivity.objects.get(id=a.id).group, True) # try with activity past due a.due_date = datetime.datetime.now() - datetime.timedelta(days=1) a.save() submit_dict['due_date_0'] = str(a.due_date.date()) submit_dict['group'] = '0' response = client.post(url, submit_dict) self.assertEqual( response.status_code, 200) # error on form -> 200 and back to form with error self.assertContains(response, "due date has passed") # try with a mark in the system a.due_date = datetime.datetime.now() + datetime.timedelta(days=1) a.save() submit_dict['due_date_0'] = str(a.due_date.date()) submit_dict['group'] = '0' g = NumericGrade(activity=a, member=m, value=2, flag="GRAD") g.save(entered_by='ggbaker') response = client.post(url, submit_dict) self.assertEqual(response.status_code, 200) self.assertContains(response, "grades have already been given") # try with a submission in the system g.flag = "NOGR" g.save(entered_by='ggbaker') s = StudentSubmission(activity=a, member=m) s.save() response = client.post(url, submit_dict) self.assertEqual(response.status_code, 200) self.assertContains(response, "submissions have already been made")
def test_formulas(self): """ Test the formula parsing & evaluation. """ # set up course and related data s, c = create_offering() p = Person.objects.get(userid="0aaa0") m = Member(person=p, offering=c, role="STUD", credits=3, added_reason="UNK") m.save() a = NumericActivity(name="Paragraph", short_name=u"\u00b6", status="RLS", offering=c, position=3, max_grade=40, percent=5) a.save() g = NumericGrade(activity=a, member=m, value="4.5", flag="CALC") g.save(entered_by='ggbaker') a1 = NumericActivity(name="Assignment #1", short_name="A1", status="RLS", offering=c, position=1, max_grade=15, percent=10) a1.save() g = NumericGrade(activity=a1, member=m, value=10, flag="GRAD") g.save(entered_by='ggbaker') a2 = NumericActivity(name="Assignment #2", short_name="A2", status="URLS", offering=c, position=2, max_grade=40, percent=20) a2.save(entered_by='ggbaker') g = NumericGrade(activity=a2, member=m, value=30, flag="GRAD") g.save(entered_by='ggbaker') ca = CalNumericActivity(name="Final Grade", short_name=u"FG", status="RLS", offering=c, position=4, max_grade=1) ca.save() activities = NumericActivity.objects.filter(offering=c) act_dict = activities_dictionary(activities) # make sure a formula can be pickled and unpickled safely (i.e. can be cached) tree = parse("sum([Assignment #1], [A1], [A2])/20*-3", c, ca) p = pickle.dumps(tree) tree2 = pickle.loads(p) self.assertEqual(tree, tree2) # check that it found the right list of columns used self.assertEqual(cols_used(tree), set(['A1', 'A2', 'Assignment #1'])) # test parsing and evaluation to make sure we get the right values out for expr, correct in test_formulas: tree = parse(expr, c, ca) res = eval_parse(tree, ca, act_dict, m, False) self.assertAlmostEqual(correct, res, msg=u"Incorrect result for %s"%(expr,)) # test some badly-formed stuff for appropriate exceptions tree = parse("1 + BEST(3, [A1], [A2])", c, ca) self.assertRaises(EvalException, eval_parse, tree, ca, act_dict, m, True) tree = parse("1 + BEST(0, [A1], [A2])", c, ca) self.assertRaises(EvalException, eval_parse, tree, ca, act_dict, m, True) tree = parse("[Foo] /2", c, ca) self.assertRaises(KeyError, eval_parse, tree, ca, act_dict, m, True) tree = parse("[a1] /2", c, ca) self.assertRaises(KeyError, eval_parse, tree, ca, act_dict, m, True) self.assertRaises(ParseException, parse, "AVG()", c, ca) self.assertRaises(ParseException, parse, "(2+3*84", c, ca) self.assertRaises(ParseException, parse, "2+3**84", c, ca) self.assertRaises(ParseException, parse, "AVG(2,3,4", c, ca) self.assertRaises(ParseException, parse, "{something}", c, ca) # test visible/invisible switching tree = parse("[Assignment #2]", c, ca) res = eval_parse(tree, ca, act_dict, m, True) self.assertAlmostEqual(res, 0.0) res = eval_parse(tree, ca, act_dict, m, False) self.assertAlmostEqual(res, 30.0) # test unreleased/missing grade conditions expr = "[Assignment #2]" tree = parse(expr, c, ca) # unreleased assignment (with grade) a2.status='URLS' a2.save() activities = NumericActivity.objects.filter(offering=c) act_dict = activities_dictionary(activities) res = eval_parse(tree, ca, act_dict, m, True) self.assertAlmostEqual(res, 0.0) # explicit no grade (released assignment) g.flag="NOGR" g.save(entered_by='ggbaker') a2.status='RLS' a2.save(entered_by='ggbaker') activities = NumericActivity.objects.filter(offering=c) act_dict = activities_dictionary(activities) res = eval_parse(tree, ca, act_dict, m, True) self.assertAlmostEqual(res, 0.0) # no grade in database (released assignment) g.delete() activities = NumericActivity.objects.filter(offering=c) act_dict = activities_dictionary(activities) res = eval_parse(tree, ca, act_dict, m, True) self.assertAlmostEqual(res, 0.0) # test [[activitytotal]] expr = "[[activitytotal]]" tree = parse(expr, c, ca) res = eval_parse(tree, ca, act_dict, m, True) self.assertAlmostEqual(res, 7.229166666)
def test_group_student(self): """ Check out group pages for student: go through the whole group-creation process from the student side. """ s, c = create_offering() a = NumericActivity(name="Assignment 1", short_name="A1", status="URLS", offering=c, position=3, max_grade=20, group=True) a.save() a1 = a a = NumericActivity(name="Assignment 2", short_name="A2", status="URLS", offering=c, position=6, max_grade=20, group=True) a.save() userid1 = "0aaa6" userid2 = "0aaa0" userid3 = "0aaa1" userid4 = "0aaa2" for u in [userid1, userid2, userid3, userid4]: p = Person.objects.get(userid=u) m = Member(person=p, offering=c, role="STUD", credits=3, career="UGRD", added_reason="UNK") m.save() client = Client() client.login_user(userid1) # group management screen url = reverse('groups.views.groupmanage', kwargs={'course_slug': c.slug}) response = basic_page_tests(self, client, url) self.assertContains(response, "You don't belong to any group") url = reverse('groups.views.create', kwargs={'course_slug': c.slug}) self.assertContains(response, 'href="%s"'%(url)) # group creation form response = basic_page_tests(self, client, url) # submit group create url = reverse('groups.views.submit', kwargs={'course_slug': c.slug}) response = client.post(url, {"GroupName": "Test Group", "a1-selected": True, "a2-selected": False}) self.assertEquals(response.status_code, 302) gs = Group.objects.filter(courseoffering=c) self.assertEquals(len(gs), 1) self.assertEquals(gs[0].name, "Test Group") self.assertEquals(gs[0].manager.person.userid, userid1) gms = GroupMember.objects.filter(group__courseoffering=c) self.assertEquals(len(gms), 1) self.assertEquals(gms[0].student.person.userid, userid1) self.assertEquals(gms[0].confirmed, True) # member invite form url = reverse('groups.views.invite', kwargs={'course_slug': c.slug, 'group_slug':'g-test-group'}) response = basic_page_tests(self, client, url) # submit invite form: invite userid2 and userid3 response = client.post(url, {"name": userid2}) response = client.post(url, {"name": userid3}) self.assertEquals(response.status_code, 302) gms = GroupMember.objects.filter(group__courseoffering=c, student__person__userid__in=[userid2,userid3]) self.assertEquals(len(gms), 2) self.assertEquals(gms[0].confirmed, False) self.assertEquals(gms[1].confirmed, False) # log in as userid2 and confirm client.login_user(userid2) url = reverse('groups.views.groupmanage', kwargs={'course_slug': c.slug}) response = basic_page_tests(self, client, url) self.assertContains(response, ", "+userid1) self.assertContains(response, ", "+userid2+" (unconfirmed)") url = reverse('groups.views.join', kwargs={'course_slug': c.slug, 'group_slug':'g-test-group'}) response = client.post(url) self.assertEquals(response.status_code, 302) gms = GroupMember.objects.filter(group__courseoffering=c, student__person__userid=userid2) self.assertEquals(len(gms), 1) self.assertEquals(gms[0].confirmed, True) # log in as userid3 and reject client.login_user(userid3) url = reverse('groups.views.reject', kwargs={'course_slug': c.slug, 'group_slug':'g-test-group'}) response = client.post(url) self.assertEquals(response.status_code, 302) gms = GroupMember.objects.filter(group__courseoffering=c, student__person__userid=userid3) self.assertEquals(len(gms), 0) # inviting userid4 shouldn't work if already in a group m = Member.objects.get(person__userid=userid4, offering=c) g = Group(name="Other Group", manager=m, courseoffering=c) g.save() gm = GroupMember(group=g, student=m, confirmed=True, activity=a1) gm.save() client.login_user(userid1) url = reverse('groups.views.invite', kwargs={'course_slug': c.slug, 'group_slug':'g-test-group'}) response = client.post(url, {"name": userid4}) gms = GroupMember.objects.filter(group__courseoffering=c, student__person__userid=userid4) self.assertEqual(len(gms), 1) self.assertEqual(gms[0].group.slug, 'g-other-group')