def test_delete_prerequisites(self): skill_graph = SkillGraph.load() src_skill = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC)) tgt_skill = skill_graph.add(Skill.build(SKILL_NAME_2, SKILL_DESC_2)) skill_graph.add_prerequisite(tgt_skill.id, src_skill.id) skill_graph = SkillGraph.load() self.assertEqual(1, len(skill_graph.prerequisites(tgt_skill.id))) # delete prerequisite actions.login(ADMIN_EMAIL) xsrf_token = crypto.XsrfTokenManager.create_xsrf_token(self.XSRF_TOKEN) response = self._put( version='1', name=tgt_skill.name, description=tgt_skill.description, prerequisite_ids=[], xsrf_token=xsrf_token, key=tgt_skill.id) self.assertEqual(200, response['status']) self.assertEqual('Saved.', response['message']) skill_graph = SkillGraph.load() prerequisites = skill_graph.prerequisites(tgt_skill.id) self.assertEqual(0, len(prerequisites))
def test_add_prerequisites(self): skill_graph = SkillGraph.load() src_skill = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC)) tgt_skill = skill_graph.add(Skill.build(SKILL_NAME_2, SKILL_DESC_2)) # add a prerequisite actions.login(ADMIN_EMAIL) xsrf_token = crypto.XsrfTokenManager.create_xsrf_token(self.XSRF_TOKEN) response = self._put( version='1', name=SKILL_NAME_3, description=SKILL_DESC_3, prerequisite_ids=[src_skill.id], xsrf_token=xsrf_token, key=tgt_skill.id) self.assertEqual(200, response['status']) self.assertEqual('Saved.', response['message']) payload = transforms.loads(response['payload']) tgt_key = payload['key'] skill_graph = SkillGraph.load() tgt_skill = skill_graph.get(tgt_key) self.assertEqual(2, len(skill_graph.skills)) prerequisites = skill_graph.prerequisites(tgt_key) self.assertEqual(1, len(prerequisites)) self.assertEqual(src_skill.id, prerequisites[0].id) self.assertEqual(tgt_skill.name, SKILL_NAME_3) self.assertEqual(tgt_skill.description, SKILL_DESC_3)
def test_multiple_successors(self): skill_graph = SkillGraph.load() skill_1 = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC)) skill_2 = skill_graph.add(Skill.build(SKILL_NAME_2, SKILL_DESC_2)) skill_3 = skill_graph.add(Skill.build(SKILL_NAME_3, SKILL_DESC_3)) # Skills 2 and 3 are successors of Skill 1 skill_graph.add_prerequisite(skill_2.id, skill_1.id) skill_graph.add_prerequisite(skill_3.id, skill_1.id) skill_graph = SkillGraph.load() successor_ids = {s.id for s in skill_graph.successors(skill_1.id)} self.assertEqual({skill_2.id, skill_3.id}, successor_ids)
def test_get_skill_list(self): skill_graph = SkillGraph.load() skill_1 = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC)) skill_2 = skill_graph.add(Skill.build(SKILL_NAME_2, SKILL_DESC_2)) skill_3 = skill_graph.add(Skill.build(SKILL_NAME_3, SKILL_DESC_3)) actions.login(ADMIN_EMAIL) response = transforms.loads(self.get(self.URL).body) self.assertEqual(200, response['status']) self.assertIn('xsrf_token', response) skill_list = transforms.loads(response['payload'])['skill_list'] self.assertEqual(3, len(skill_list)) expected_skill_list = [ { 'id': skill_1.id, 'name': skill_1.name, 'description': skill_1.description}, { 'id': skill_2.id, 'name': skill_2.name, 'description': skill_2.description}, { 'id': skill_3.id, 'name': skill_3.name, 'description': skill_3.description}] self.assertEqual(expected_skill_list, skill_list)
def test_add_loop_rejected(self): """Test that cannot add a skill with a length-1 cycle.""" skill_graph = SkillGraph.load() skill_1 = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC)) with self.assertRaises(AssertionError): skill_graph.add_prerequisite(skill_1.id, skill_1.id)
def test_add_prerequisite(self): skill_graph = SkillGraph.load() skill_1 = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC)) skill_2 = skill_graph.add(Skill.build(SKILL_NAME_2, SKILL_DESC_2)) # Skill 1 is a prerequisite for Skill 2 skill_graph.add_prerequisite(skill_2.id, skill_1.id) skill_graph = SkillGraph.load() self.assertEqual(1, len(skill_graph.prerequisites(skill_2.id))) self.assertEqual( skill_1.id, skill_graph.prerequisites(skill_2.id)[0].id) self.assertEqual(1, len(skill_graph.successors(skill_1.id))) self.assertEqual( skill_2.id, skill_graph.successors(skill_1.id)[0].id)
def test_add_duplicate_prerequisites_rejected(self): skill_graph = SkillGraph.load() skill_1 = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC)) skill_2 = skill_graph.add(Skill.build(SKILL_NAME_2, SKILL_DESC_2)) skill_graph.add_prerequisite(skill_2.id, skill_1.id) with self.assertRaises(AssertionError): skill_graph.add_prerequisite(skill_2.id, skill_1.id)
def test_add_skill_twice_is_rejected(self): skill_graph = SkillGraph.load() # Add a single skill skill = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC)) self.assertEqual(1, len(skill_graph.skills)) # Retrieve the skill by id and add it again with self.assertRaises(AssertionError): skill_graph.add(skill)
def test_delete_prerequisite(self): skill_graph = SkillGraph.load() skill_1 = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC)) skill_2 = skill_graph.add(Skill.build(SKILL_NAME_2, SKILL_DESC_2)) skill_3 = skill_graph.add(Skill.build(SKILL_NAME_3, SKILL_DESC_3)) # Skills 1 and 2 are prerequisites for Skill 3 skill_graph.add_prerequisite(skill_3.id, skill_1.id) skill_graph.add_prerequisite(skill_3.id, skill_2.id) skill_graph = SkillGraph.load() self.assertEqual(2, len(skill_graph.prerequisites(skill_3.id))) # Delete skill 1 as a prerequisite and expect that only skill 2 is a # prerequisite now skill_graph.delete_prerequisite(skill_3.id, skill_1.id) self.assertEqual(1, len(skill_graph.prerequisites(skill_3.id))) self.assertEqual( skill_2.id, skill_graph.prerequisites(skill_3.id)[0].id)
def test_delete_skill(self): # Skill map is initially empty skill_graph = SkillGraph.load() self.assertEqual(0, len(skill_graph.skills)) # Add a single skill skill = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC)) self.assertEqual(1, len(skill_graph.skills)) # Delete the skill and expect empty skill_graph.delete(skill.id) self.assertEqual(0, len(skill_graph.skills))
def test_add_skill(self): # Skill map is initially empty skill_graph = SkillGraph.load() self.assertEqual(0, len(skill_graph.skills)) # Add a single skill skill = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC)) self.assertEqual(1, len(skill_graph.skills)) # Retrieve the skill by id self.assertEqual(SKILL_NAME, skill.name) self.assertEqual(SKILL_DESC, skill.description)
def test_create_skill(self): skill_graph = SkillGraph.load() self.assertEqual(0, len(skill_graph.skills)) actions.login(ADMIN_EMAIL) xsrf_token = crypto.XsrfTokenManager.create_xsrf_token(self.XSRF_TOKEN) response = self._put( version='1', name=SKILL_NAME, description=SKILL_DESC, xsrf_token=xsrf_token) self.assertEqual(200, response['status']) self.assertEqual('Saved.', response['message']) payload = transforms.loads(response['payload']) key = payload['key'] skill_graph = SkillGraph.load() self.assertEqual(1, len(skill_graph.skills)) skill = skill_graph.get(key) self.assertEqual(key, skill.id) self.assertEqual(SKILL_NAME, skill.name) self.assertEqual(SKILL_DESC, skill.description)
def test_add_missing_prerequisites_rejected(self): skill_graph = SkillGraph.load() with self.assertRaises(AssertionError): skill_graph.add_prerequisite('missing', 'also missing') skill_1 = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC)) with self.assertRaises(AssertionError): skill_graph.add_prerequisite('missing', skill_1.id) with self.assertRaises(AssertionError): skill_graph.add_prerequisite(skill_1.id, 'also missing')
def test_get_lessons_returns_empty_list_when_no_skills_assigned(self): skill_graph = SkillGraph.load() skill = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC)) skill_map = SkillMap.load(self.course) # look up lessons by skill id lessons = skill_map.get_lessons_for_skill(skill) self.assertIsNotNone(lessons) self.assertEqual(0, len(lessons)) # look up lessons by skill lessons = skill_map.get_lessons_for_skill(skill) self.assertIsNotNone(lessons) self.assertEqual(0, len(lessons))
def test_topo_sort(self): # a # \ # d # / \ # b f # / # c--e skill_graph = SkillGraph.load() sa = skill_graph.add(Skill.build('a', '')) sb = skill_graph.add(Skill.build('b', '')) sd = skill_graph.add(Skill.build('d', '')) skill_graph.add_prerequisite(sd.id, sa.id) skill_graph.add_prerequisite(sd.id, sb.id) sc = skill_graph.add(Skill.build('c', '')) se = skill_graph.add(Skill.build('e', '')) skill_graph.add_prerequisite(se.id, sc.id) sf = skill_graph.add(Skill.build('f', '')) skill_graph.add_prerequisite(sf.id, se.id) skill_map = SkillMap.load(self.course) self.assertEqual(6, len(skill_map.skills())) # verify topological co-sets expected = { 0: set([sa.id, sb.id, sc.id]), 1: set([se.id, sd.id]), 2: set([sf.id])} for ind, co_set in enumerate(skill_map._topo_sort()): self.assertEqual(expected[ind], co_set) # verify sorting skills by lesson expected = ['a', 'b', 'd', 'c', 'e', 'f'] self.assertEqual( expected, [s.name for s in skill_map.skills(sort_by='lesson')]) # verify sorting skills by name expected = ['a', 'b', 'c', 'd', 'e', 'f'] self.assertEqual( expected, [s.name for s in skill_map.skills(sort_by='name')]) # verify sorting skills by prerequisites expected = ['a', 'b', 'c', 'd', 'e', 'f'] actual = [s.name for s in skill_map.skills(sort_by='prerequisites')] self.assertEqual(expected, actual)
def test_skills_table(self): skill_graph = SkillGraph.load() skill = skill_graph.add( Skill.build(name=SKILL_NAME, description=SKILL_DESC)) response = self.get(self.SKILL_MAP_URL) self.assertEqual(200, response.status_int) dom = self.parse_html_string(response.body) table = dom.find('.//table[@class="skill-map-table"]') rows = table.findall('./tbody/tr') self.assertEqual(1, len(rows)) expected_row_data = [skill.name, skill.description, '', ''] for ind, td in enumerate(rows[0].findall('td')): td_text = (''.join(td.itertext())).strip() self.assertEqual(expected_row_data[ind], td_text) skill_count = table.find('.//span[@class="skill_count"]') self.assertEqual('(1)', ''.join(skill_count.itertext()).strip())
def test_delete_missing_prerequisites_rejected(self): skill_graph = SkillGraph.load() with self.assertRaises(AssertionError): skill_graph.delete_prerequisite('missing', 'also missing') skill_1 = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC)) skill_2 = skill_graph.add(Skill.build(SKILL_NAME_2, SKILL_DESC_2)) with self.assertRaises(AssertionError): skill_graph.delete_prerequisite('missing', skill_1.id) with self.assertRaises(AssertionError): skill_graph.delete_prerequisite(skill_1.id, 'also missing') # Also reject deletion of a prerequisite if the skill exists but is not # currently a prerequisite with self.assertRaises(AssertionError): skill_graph.delete_prerequisite(skill_1.id, skill_2.id)
def test_skills_table_with_prerequisites(self): skill_graph = SkillGraph.load() src_skill = skill_graph.add( Skill.build(name=SKILL_NAME, description=SKILL_DESC)) tgt_skill = skill_graph.add( Skill.build(name=SKILL_NAME_2, description=SKILL_DESC_2)) skill_graph.add_prerequisite(tgt_skill.id, src_skill.id) response = self.get(self.SKILL_MAP_URL) self.assertEqual(200, response.status_int) dom = self.parse_html_string(response.body) table = dom.find('.//table[@class="skill-map-table"]') rows = table.findall('./tbody/tr') self.assertEqual(2, len(rows)) expected_row_data = [ [tgt_skill.name, tgt_skill.description, src_skill.name, ''], [src_skill.name, src_skill.description, '', '']] for i, row in enumerate(rows): for j, td in enumerate(row.findall('td')): td_text = (''.join(td.itertext())).strip() self.assertEqual(expected_row_data[i][j], td_text)
def test_get_lessons_for_skill(self): skill_graph = SkillGraph.load() skill_1 = skill_graph.add(Skill.build(SKILL_NAME, SKILL_DESC)) skill_2 = skill_graph.add(Skill.build(SKILL_NAME_2, SKILL_DESC_2)) # lesson 1 has one skill self.lesson1.properties[LESSON_SKILL_LIST_KEY] = [skill_1.id] # lesson 2 has no skills # lesson 3 has both skills self.lesson3.properties[LESSON_SKILL_LIST_KEY] = [ skill_1.id, skill_2.id] self.course.save() skill_map = SkillMap.load(self.course) lessons = skill_map.get_lessons_for_skill(skill_1) self.assertEqual(2, len(lessons)) self.assertEqual(self.lesson1.lesson_id, lessons[0].lesson_id) self.assertEqual(self.lesson3.lesson_id, lessons[1].lesson_id) lessons = skill_map.get_lessons_for_skill(skill_2) self.assertEqual(1, len(lessons)) self.assertEqual(self.lesson3.lesson_id, lessons[0].lesson_id)