def test_get_skill_from_model_with_invalid_misconceptions_schema_version( self): commit_cmd = skill_domain.SkillChange( {'cmd': skill_domain.CMD_CREATE_NEW}) example_1 = skill_domain.WorkedExample( state_domain.SubtitledHtml('2', '<p>Example Question 1</p>'), state_domain.SubtitledHtml('3', '<p>Example Explanation 1</p>')) model = skill_models.SkillModel( id='skill_id', description='description', language_code='en', misconceptions=[], rubrics=[], next_misconception_id=0, misconceptions_schema_version=0, rubric_schema_version=3, skill_contents_schema_version=2, all_questions_merged=False, skill_contents=skill_domain.SkillContents( state_domain.SubtitledHtml('1', '<p>Explanation</p>'), [example_1], state_domain.RecordedVoiceovers.from_dict( {'voiceovers_mapping': { '1': {}, '2': {}, '3': {} }}), state_domain.WrittenTranslations.from_dict( {'translations_mapping': { '1': {}, '2': {}, '3': {} }})).to_dict()) commit_cmd_dicts = [commit_cmd.to_dict()] model.commit(self.user_id_admin, 'skill model created', commit_cmd_dicts) with self.assertRaisesRegex( Exception, 'Sorry, we can only process v1-v%d misconception schemas at ' 'present.' % feconf.CURRENT_MISCONCEPTIONS_SCHEMA_VERSION): skill_fetchers.get_skill_from_model(model)
def test_conversion_to_and_from_dict(self): """Test that to_dict and from_dict preserve all data within a skill_contents and misconception object. """ example_1 = skill_domain.WorkedExample( state_domain.SubtitledHtml('2', '<p>Example Question 1</p>'), state_domain.SubtitledHtml('3', '<p>Example Answer 1</p>')) skill_contents = skill_domain.SkillContents( state_domain.SubtitledHtml('1', '<p>Explanation</p>'), [example_1], state_domain.RecordedVoiceovers.from_dict( {'voiceovers_mapping': { '1': {}, '2': {}, '3': {} }}), state_domain.WrittenTranslations.from_dict( {'translations_mapping': { '1': {}, '2': {}, '3': {} }})) skill_contents_dict = skill_contents.to_dict() skill_contents_from_dict = skill_domain.SkillContents.from_dict( skill_contents_dict) misconceptions = skill_domain.Misconception(self.MISCONCEPTION_ID, 'Tag Name', '<p>Description</p>', '<p>Feedback</p>', True) misconceptions_dict = misconceptions.to_dict() misconceptions_from_dict = skill_domain.Misconception.from_dict( misconceptions_dict) rubric = skill_domain.Rubric(constants.SKILL_DIFFICULTIES[0], ['<p>Explanation</p>']) rubric_dict = rubric.to_dict() rubric_from_dict = skill_domain.Rubric.from_dict(rubric_dict) self.assertEqual(skill_contents_from_dict.to_dict(), skill_contents_dict) self.assertEqual(misconceptions_from_dict.to_dict(), misconceptions_dict) self.assertEqual(rubric_from_dict.to_dict(), rubric_dict)
def test_conversion_to_and_from_dict(self): """Test that to_dict and from_dict preserve all data within a skill_contents and misconception object. """ skill_contents = skill_domain.SkillContents( state_domain.SubtitledHtml('1', 'Explanation'), [ state_domain.SubtitledHtml('2', 'Example 1')], {}) skill_contents_dict = skill_contents.to_dict() skill_contents_from_dict = skill_domain.SkillContents.from_dict( skill_contents_dict) misconceptions = skill_domain.Misconception( self.MISCONCEPTION_ID, 'Tag Name', 'Description', 'Feedback') misconceptions_dict = misconceptions.to_dict() misconceptions_from_dict = skill_domain.Misconception.from_dict( misconceptions_dict) self.assertEqual( skill_contents_from_dict.to_dict(), skill_contents_dict) self.assertEqual( misconceptions_from_dict.to_dict(), misconceptions_dict)
def setUp(self): """Before each individual test, create a dummy skill.""" super(ConceptCardDataHandlerTest, self).setUp() self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.skill_contents = skill_domain.SkillContents( state_domain.SubtitledHtml('1', 'Skill Explanation'), [ state_domain.SubtitledHtml('2', 'Example 1'), state_domain.SubtitledHtml('3', 'Example 2') ], {}) self.admin = user_services.UserActionsInfo(self.admin_id) self.skill_id = skill_services.get_new_skill_id() self.save_new_skill(self.skill_id, self.admin_id, 'Description', skill_contents=self.skill_contents)
def test_get_suggestions_after_updating_suggestion_summary(self): self.login(self.EDITOR_EMAIL) response_dict = self.get_json( '%s/%s' % (feconf.FEEDBACK_THREADLIST_URL_PREFIX, self.EXP_ID_1)) thread_id = response_dict['feedback_thread_dicts'][0]['thread_id'] thread_url = '%s/%s' % ( feconf.LEARNER_DASHBOARD_FEEDBACK_THREAD_DATA_URL, thread_id) response_dict = self.get_json(thread_url) messages_summary = response_dict['message_summary_list'][0] self.assertEqual(messages_summary['author_username'], self.EDITOR_USERNAME) self.assertTrue(messages_summary['author_picture_data_url'].startswith( 'data:image/png;')) self.assertFalse(messages_summary.get('suggestion_html')) self.assertFalse(messages_summary.get('current_content_html')) self.assertFalse(messages_summary.get('description')) new_content = state_domain.SubtitledHtml('content', 'new content html').to_dict() change_cmd = { 'cmd': exp_domain.CMD_EDIT_STATE_PROPERTY, 'property_name': exp_domain.STATE_PROPERTY_CONTENT, 'state_name': 'Welcome!', 'new_value': new_content } suggestion_models.GeneralSuggestionModel.create( suggestion_models.SUGGESTION_TYPE_EDIT_STATE_CONTENT, suggestion_models.TARGET_TYPE_EXPLORATION, self.EXP_ID_1, 1, suggestion_models.STATUS_IN_REVIEW, self.editor_id, None, change_cmd, 'score category', thread_id) suggestion_thread = feedback_services.get_thread(thread_id) suggestion = suggestion_services.get_suggestion_by_id(thread_id) exploration = exp_services.get_exploration_by_id(self.EXP_ID_1) current_content_html = ( exploration.states[suggestion.change.state_name].content.html) response_dict = self.get_json(thread_url) messages_summary = response_dict['message_summary_list'][0] self.assertEqual(messages_summary['author_username'], self.EDITOR_USERNAME) self.assertTrue(messages_summary['author_picture_data_url'].startswith( 'data:image/png;')) self.assertEqual(messages_summary['suggestion_html'], 'new content html') self.assertEqual(messages_summary['current_content_html'], current_content_html) self.assertEqual(messages_summary['description'], suggestion_thread.subject) self.logout()
def test_fail_to_add_unpublished_skill_id(self): self.save_new_skill('skill_a', self.user_id_a, 'Description A', misconceptions=[], skill_contents=skill_domain.SkillContents( state_domain.SubtitledHtml('1', 'Explanation'), [state_domain.SubtitledHtml('2', 'Example 1')], { '1': {}, '2': {} }, state_domain.WrittenTranslations.from_dict({ 'translations_mapping': { '1': {}, '2': {} } }))) with self.assertRaisesRegexp( Exception, 'Cannot assign unpublished skills to a topic'): self.topic.add_uncategorized_skill_id('skill_a')
def test_skill_contents_audio_validation(self): self.skill.update_worked_examples([{ 'content_id': 'content_id_1', 'html': '<p>Hello</p>' }, { 'content_id': 'content_id_2', 'html': '<p>Hello 2</p>' }]) self.skill.skill_contents.content_ids_to_audio_translations = { 'content_id_3': {} } self._assert_validation_error( 'Expected content_ids_to_audio_translations to contain only ' 'content_ids in worked examples and explanation.') self.skill.skill_contents.worked_examples = [ state_domain.SubtitledHtml('content_id_1', '<p>Hello</p>'), state_domain.SubtitledHtml('content_id_1', '<p>Hello 2</p>') ] self._assert_validation_error('Found a duplicate content id')
def setUp(self): super(SkillServicesUnitTests, self).setUp() skill_contents = skill_domain.SkillContents( state_domain.SubtitledHtml('1', '<p>Explanation</p>'), [state_domain.SubtitledHtml('2', '<p>Example 1</p>')], state_domain.RecordedVoiceovers.from_dict( {'voiceovers_mapping': { '1': {}, '2': {} }}), state_domain.WrittenTranslations.from_dict( {'translations_mapping': { '1': {}, '2': {} }})) misconceptions = [ skill_domain.Misconception(self.MISCONCEPTION_ID_1, 'name', '<p>description</p>', '<p>default_feedback</p>') ] self.SKILL_ID = skill_services.get_new_skill_id() self.signup('*****@*****.**', 'A') self.signup(self.ADMIN_EMAIL, username=self.ADMIN_USERNAME) self.signup('*****@*****.**', username='******') self.user_id_a = self.get_user_id_from_email('*****@*****.**') self.user_id_admin = self.get_user_id_from_email(self.ADMIN_EMAIL) self.user_id_admin_2 = self.get_user_id_from_email( '*****@*****.**') self.set_admins([self.ADMIN_USERNAME, 'adm2']) self.user_a = user_services.UserActionsInfo(self.user_id_a) self.user_admin = user_services.UserActionsInfo(self.user_id_admin) self.user_admin_2 = user_services.UserActionsInfo(self.user_id_admin_2) self.skill = self.save_new_skill(self.SKILL_ID, self.USER_ID, 'Description', misconceptions=misconceptions, skill_contents=skill_contents)
def test_skill_creation_with_valid_images(self): self.login(self.CURRICULUM_ADMIN_EMAIL) csrf_token = self.get_new_csrf_token() filename = 'img.png' filename_2 = 'img_2.png' explanation_html = ( '<oppia-noninteractive-image filepath-with-value=' '""img.png"" caption-with-value="""" ' 'alt-with-value=""Image""></oppia-noninteractive-image>') explanation_html_2 = ( '<oppia-noninteractive-image filepath-with-value=' '""img_2.png"" caption-with-value="""" ' 'alt-with-value=""Image 2""></oppia-noninteractive-image>' ) rubrics = [{ 'difficulty': constants.SKILL_DIFFICULTIES[0], 'explanations': ['Explanation 1', explanation_html_2] }, { 'difficulty': constants.SKILL_DIFFICULTIES[1], 'explanations': ['Explanation 2'] }, { 'difficulty': constants.SKILL_DIFFICULTIES[2], 'explanations': ['Explanation 3'] }] post_data = { 'description': 'Skill Description', 'rubrics': rubrics, 'explanation_dict': state_domain.SubtitledHtml('1', explanation_html).to_dict(), 'thumbnail_filename': 'image.svg' } with python_utils.open_file(os.path.join(feconf.TESTS_DATA_DIR, 'img.png'), 'rb', encoding=None) as f: raw_image = f.read() json_response = self.post_json(self.url, post_data, csrf_token=csrf_token, upload_files=( (filename, filename, raw_image), (filename_2, filename_2, raw_image), )) skill_id = json_response['skillId'] self.assertIsNotNone( skill_fetchers.get_skill_by_id(skill_id, strict=False)) self.logout()
def test_content_ids_to_audio_translations_validation(self): self.subtopic_page_contents.content_ids_to_audio_translations = 1 self._assert_validation_error( 'Expected content_ids_to_audio_translations to be a dict') self.subtopic_page_contents.subtitled_html = ( state_domain.SubtitledHtml('content', '<p>Test</p>')) self.subtopic_page_contents.content_ids_to_audio_translations = { 'content_id_3': {} } self._assert_validation_error( 'Expected content_ids_to_audio_translations to contain ' 'only content_ids in the subtopic page.')
def test_get_skill_descriptions_by_ids(self): self.save_new_skill('skill_2', self.USER_ID, 'Description 2', misconceptions=[], skill_contents=skill_domain.SkillContents( state_domain.SubtitledHtml('1', 'Explanation'), [state_domain.SubtitledHtml('2', 'Example 1')], {})) self.save_new_skill('skill_3', self.USER_ID, 'Description 3', misconceptions=[], skill_contents=skill_domain.SkillContents( state_domain.SubtitledHtml('1', 'Explanation'), [state_domain.SubtitledHtml('2', 'Example 1')], {})) with self.swap(feconf, 'CAN_SEND_EMAILS', True): skill_descriptions = skill_services.get_skill_descriptions_by_ids( 'topic_id', [self.SKILL_ID, 'skill_2', 'skill_3']) messages = self.mail_stub.get_sent_messages( to=feconf.ADMIN_EMAIL_ADDRESS) self.assertEqual(len(messages), 0) skill_services.delete_skill(self.USER_ID, 'skill_2') skill_descriptions = skill_services.get_skill_descriptions_by_ids( 'topic_id', [self.SKILL_ID, 'skill_2', 'skill_3']) messages = self.mail_stub.get_sent_messages( to=feconf.ADMIN_EMAIL_ADDRESS) expected_email_html_body = ('The deleted skills: skill_2 are still' ' present in topic with id topic_id') self.assertEqual(len(messages), 1) self.assertIn(expected_email_html_body, messages[0].html.decode()) self.assertEqual( skill_descriptions, { self.SKILL_ID: 'Description', 'skill_2': None, 'skill_3': 'Description 3' })
def setUp(self): super(SkillFetchersUnitTests, self).setUp() example_1 = skill_domain.WorkedExample( state_domain.SubtitledHtml('2', '<p>Example Question 1</p>'), state_domain.SubtitledHtml('3', '<p>Example Explanation 1</p>')) skill_contents = skill_domain.SkillContents( state_domain.SubtitledHtml('1', '<p>Explanation</p>'), [example_1], state_domain.RecordedVoiceovers.from_dict( {'voiceovers_mapping': { '1': {}, '2': {}, '3': {} }}), state_domain.WrittenTranslations.from_dict( {'translations_mapping': { '1': {}, '2': {}, '3': {} }})) misconceptions = [ skill_domain.Misconception(self.MISCONCEPTION_ID_1, 'name', '<p>description</p>', '<p>default_feedback</p>', True) ] self.SKILL_ID = skill_services.get_new_skill_id() self.signup(self.CURRICULUM_ADMIN_EMAIL, self.CURRICULUM_ADMIN_USERNAME) self.user_id_admin = (self.get_user_id_from_email( self.CURRICULUM_ADMIN_EMAIL)) self.set_curriculum_admins([self.CURRICULUM_ADMIN_USERNAME]) self.skill = self.save_new_skill( self.SKILL_ID, self.USER_ID, description='Description', misconceptions=misconceptions, skill_contents=skill_contents, prerequisite_skill_ids=['skill_id_1', 'skill_id_2'])
def setUp(self): super(SkillDomainUnitTests, self).setUp() skill_contents = skill_domain.SkillContents( state_domain.SubtitledHtml('1', 'Explanation'), [state_domain.SubtitledHtml('2', 'Example 1')], { '1': {}, '2': {} }, state_domain.WrittenTranslations.from_dict( {'translations_mapping': { '1': {}, '2': {} }})) misconceptions = [ skill_domain.Misconception(self.MISCONCEPTION_ID, 'name', 'notes', 'default_feedback') ] self.skill = skill_domain.Skill( self.SKILL_ID, 'Description', misconceptions, skill_contents, feconf.CURRENT_MISCONCEPTIONS_SCHEMA_VERSION, feconf.CURRENT_SKILL_CONTENTS_SCHEMA_VERSION, 'en', 0, 1, None, False)
def setUp(self): super(SkillDomainUnitTests, self).setUp() example_1 = skill_domain.WorkedExample( state_domain.SubtitledHtml('2', '<p>Example Question 1</p>'), state_domain.SubtitledHtml('3', '<p>Example Explanation 1</p>')) skill_contents = skill_domain.SkillContents( state_domain.SubtitledHtml('1', '<p>Explanation</p>'), [example_1], state_domain.RecordedVoiceovers.from_dict( {'voiceovers_mapping': { '1': {}, '2': {}, '3': {} }}), state_domain.WrittenTranslations.from_dict( {'translations_mapping': { '1': {}, '2': {}, '3': {} }})) misconceptions = [ skill_domain.Misconception(self.MISCONCEPTION_ID, 'name', '<p>notes</p>', '<p>default_feedback</p>', True) ] rubrics = [ skill_domain.Rubric(constants.SKILL_DIFFICULTIES[0], ['<p>Explanation 1</p>']), skill_domain.Rubric(constants.SKILL_DIFFICULTIES[1], ['<p>Explanation 2</p>']), skill_domain.Rubric(constants.SKILL_DIFFICULTIES[2], ['<p>Explanation 3</p>']) ] self.skill = skill_domain.Skill( self.SKILL_ID, 'Description', misconceptions, rubrics, skill_contents, feconf.CURRENT_MISCONCEPTIONS_SCHEMA_VERSION, feconf.CURRENT_RUBRIC_SCHEMA_VERSION, feconf.CURRENT_SKILL_CONTENTS_SCHEMA_VERSION, 'en', 0, 1, None, False, ['skill_id_2'])
def test_conversion_to_and_from_dict(self): """Test that to_dict and from_dict preserve all data within a skill_contents and misconception object. """ audio_translation = { 'en': state_domain.AudioTranslation.from_dict({ 'filename': 'file.mp3', 'file_size_bytes': 'size', 'needs_update': True }) } skill_contents = skill_domain.SkillContents( state_domain.SubtitledHtml('1', 'Explanation'), [state_domain.SubtitledHtml('2', 'Example 1')], { '1': audio_translation, '2': {} }, state_domain.WrittenTranslations.from_dict( {'translations_mapping': { '1': {}, '2': {} }})) skill_contents_dict = skill_contents.to_dict() skill_contents_from_dict = skill_domain.SkillContents.from_dict( skill_contents_dict) misconceptions = skill_domain.Misconception(self.MISCONCEPTION_ID, 'Tag Name', 'Description', 'Feedback') misconceptions_dict = misconceptions.to_dict() misconceptions_from_dict = skill_domain.Misconception.from_dict( misconceptions_dict) self.assertEqual(skill_contents_from_dict.to_dict(), skill_contents_dict) self.assertEqual(misconceptions_from_dict.to_dict(), misconceptions_dict)
def test_get_multi_skills(self): self.save_new_skill( 'skill_a', self.user_id_admin, description='Description A', misconceptions=[], skill_contents=skill_domain.SkillContents( state_domain.SubtitledHtml('1', '<p>Explanation</p>'), [ state_domain.SubtitledHtml('2', '<p>Example 1</p>')], state_domain.RecordedVoiceovers.from_dict( {'voiceovers_mapping': {'1': {}, '2': {}}}), state_domain.WrittenTranslations.from_dict( {'translations_mapping': {'1': {}, '2': {}}}))) self.save_new_skill( 'skill_b', self.user_id_admin, description='Description B', misconceptions=[], skill_contents=skill_domain.SkillContents( state_domain.SubtitledHtml('1', '<p>Explanation</p>'), [ state_domain.SubtitledHtml('2', '<p>Example 1</p>')], state_domain.RecordedVoiceovers.from_dict( {'voiceovers_mapping': {'1': {}, '2': {}}}), state_domain.WrittenTranslations.from_dict( {'translations_mapping': {'1': {}, '2': {}}}))) skills = skill_services.get_multi_skills(['skill_a', 'skill_b']) self.assertEqual(len(skills), 2) self.assertEqual(skills[0].id, 'skill_a') self.assertEqual(skills[0].description, 'Description A') self.assertEqual(skills[0].misconceptions, []) self.assertEqual(skills[1].id, 'skill_b') self.assertEqual(skills[1].description, 'Description B') self.assertEqual(skills[1].misconceptions, []) with self.assertRaisesRegexp( Exception, 'No skill exists for ID skill_c'): skill_services.get_multi_skills(['skill_a', 'skill_c'])
def test_cron_accept_stale_suggestions_handler(self): self.login(self.ADMIN_EMAIL, is_super_admin=True) self.save_new_valid_exploration('exp_id', self.admin_id, title='A title', category='Algebra') author_id = self.get_user_id_from_email(self.ADMIN_EMAIL) new_content = state_domain.SubtitledHtml( 'content', '<p>new suggestion content</p>').to_dict() change = { 'cmd': 'edit_state_property', 'property_name': 'content', 'state_name': 'Introduction', 'new_value': new_content } suggestion_services.create_suggestion( suggestion_models.SUGGESTION_TYPE_EDIT_STATE_CONTENT, suggestion_models.TARGET_TYPE_EXPLORATION, 'exp_id', 1, author_id, change, 'change title') exploration = exp_fetchers.get_exploration_by_id('exp_id') self.assertEqual(exploration.states['Introduction'].content.to_dict(), { 'content_id': 'content', 'html': '' }) threshold_time_before_accept_swap = self.swap( suggestion_models, 'THRESHOLD_TIME_BEFORE_ACCEPT_IN_MSECS', 0) auto_accept_suggestions_swap = self.swap( feconf, 'ENABLE_AUTO_ACCEPT_OF_SUGGESTIONS', True) with threshold_time_before_accept_swap, self.testapp_swap, ( auto_accept_suggestions_swap): self.assertEqual( len(suggestion_services.get_all_stale_suggestions()), 1) self.get_html_response( '/cron/suggestions/accept_stale_suggestions') self.assertEqual( len(suggestion_services.get_all_stale_suggestions()), 0) exploration = exp_fetchers.get_exploration_by_id('exp_id') self.assertEqual(exploration.states['Introduction'].content.to_dict(), { 'content_id': 'content', 'html': '<p>new suggestion content</p>' })
def setUp(self): """Before each individual test, create a dummy skill.""" super(ConceptCardDataHandlerTest, self).setUp() self.signup(self.CURRICULUM_ADMIN_EMAIL, self.CURRICULUM_ADMIN_USERNAME) self.admin_id = self.get_user_id_from_email(self.CURRICULUM_ADMIN_EMAIL) self.set_curriculum_admins([self.CURRICULUM_ADMIN_USERNAME]) example_1 = skill_domain.WorkedExample( state_domain.SubtitledHtml('2', '<p>Example Question 1</p>'), state_domain.SubtitledHtml('3', '<p>Example Explanation 1</p>') ) example_2 = skill_domain.WorkedExample( state_domain.SubtitledHtml('4', '<p>Example Question 2</p>'), state_domain.SubtitledHtml('5', '<p>Example Explanation 2</p>') ) self.skill_contents = skill_domain.SkillContents( state_domain.SubtitledHtml( '1', '<p>Skill Explanation</p>'), [example_1, example_2], state_domain.RecordedVoiceovers.from_dict({ 'voiceovers_mapping': { '1': {}, '2': {}, '3': {}, '4': {}, '5': {} } }), state_domain.WrittenTranslations.from_dict({ 'translations_mapping': { '1': {}, '2': {}, '3': {}, '4': {}, '5': {} } }) ) self.skill_contents_1 = skill_domain.SkillContents( state_domain.SubtitledHtml( '1', '<p>Skill Explanation 1</p>'), [example_1, example_2], state_domain.RecordedVoiceovers.from_dict({ 'voiceovers_mapping': { '1': {}, '2': {}, '3': {}, '4': {}, '5': {} } }), state_domain.WrittenTranslations.from_dict({ 'translations_mapping': { '1': {}, '2': {}, '3': {}, '4': {}, '5': {} } }) ) self.admin = user_services.get_user_actions_info(self.admin_id) self.skill_id = skill_services.get_new_skill_id() self.save_new_skill( self.skill_id, self.admin_id, description='Description', skill_contents=self.skill_contents) self.skill_id_1 = skill_services.get_new_skill_id() self.save_new_skill( self.skill_id_1, self.admin_id, description='Description', skill_contents=self.skill_contents_1) self.skill_id_2 = skill_services.get_new_skill_id()
def test_subtitled_html_validation(self): """Test validation of subtitled HTML.""" subtitled_html = state_domain.SubtitledHtml('content_id', 'some html') subtitled_html.validate() with self.assertRaisesRegexp(utils.ValidationError, 'Invalid content HTML'): with self.swap(subtitled_html, 'html', 20): subtitled_html.validate() with self.assertRaisesRegexp( utils.ValidationError, 'Expected content id to be a string, ' + 'received 20'): with self.swap(subtitled_html, 'content_id', 20): subtitled_html.validate()
def test_skill_creation_in_invalid_topic(self): self.login(self.ADMIN_EMAIL) csrf_token = self.get_new_csrf_token() payload = { 'description': 'Skill Description', 'linked_topic_ids': ['topic'], 'rubrics': [], 'explanation_dict': state_domain.SubtitledHtml( '1', '<p>Explanation</p>').to_dict() } json_response = self.post_json( self.url, payload, csrf_token=csrf_token, expected_status_int=400) self.assertEqual(json_response['status_code'], 400) self.logout()
def test_skill_creation_with_invalid_images(self): self.login(self.ADMIN_EMAIL) csrf_token = self.get_new_csrf_token() explanation_html = ( '<oppia-noninteractive-image filepath-with-value=' '""img.svg"" caption-with-value="""" ' 'alt-with-value=""Image""></oppia-noninteractive-image>') rubrics = [{ 'difficulty': constants.SKILL_DIFFICULTIES[0], 'explanations': ['Explanation 1'] }, { 'difficulty': constants.SKILL_DIFFICULTIES[1], 'explanations': ['Explanation 2'] }, { 'difficulty': constants.SKILL_DIFFICULTIES[2], 'explanations': ['Explanation 3'] }] post_data = { 'description': 'Skill Description', 'rubrics': rubrics, 'explanation_dict': state_domain.SubtitledHtml('1', explanation_html).to_dict(), 'thumbnail_filename': 'image.svg' } response_dict = self.post_json(self.url, post_data, csrf_token=csrf_token, expected_status_int=400) self.assertIn('No image data provided for file with name img.svg', response_dict['error']) large_image = '<svg><path d="%s" /></svg>' % ( 'M150 0 L75 200 L225 200 Z ' * 4000) response_dict = self.post_json(self.url, post_data, csrf_token=csrf_token, upload_files=(('img.svg', 'img.svg', large_image), ), expected_status_int=400) self.assertIn('Image exceeds file size limit of 100 KB.', response_dict['error']) self.logout()
def test_migrate_misconceptions_to_latest_schema(self): commit_cmd = skill_domain.SkillChange({ 'cmd': skill_domain.CMD_CREATE_NEW }) explanation_content_id = feconf.DEFAULT_SKILL_EXPLANATION_CONTENT_ID skill_contents = skill_domain.SkillContents( state_domain.SubtitledHtml( explanation_content_id, feconf.DEFAULT_SKILL_EXPLANATION), [], state_domain.RecordedVoiceovers.from_dict({ 'voiceovers_mapping': { explanation_content_id: {} } }), state_domain.WrittenTranslations.from_dict({ 'translations_mapping': { explanation_content_id: {} } })) model = skill_models.SkillModel( id='skill_id', description='description', language_code='en', misconceptions=[{ 'id': 1, 'name': 'name', 'notes': 'notes', 'feedback': 'default_feedback' }], rubrics=[], skill_contents=skill_contents.to_dict(), next_misconception_id=2, misconceptions_schema_version=1, rubric_schema_version=1, skill_contents_schema_version=1, all_questions_merged=False ) commit_cmd_dicts = [commit_cmd.to_dict()] model.commit( 'user_id_admin', 'skill model created', commit_cmd_dicts) current_schema_version_swap = self.swap( feconf, 'CURRENT_MISCONCEPTIONS_SCHEMA_VERSION', 2) with current_schema_version_swap: skill = skill_services.get_skill_from_model(model) self.assertEqual(skill.misconceptions_schema_version, 2) self.assertEqual(skill.misconceptions[0].must_be_addressed, True)
def setUp(self): """Before each individual test, create a dummy skill.""" super(ConceptCardDataHandlerTest, self).setUp() self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.skill_contents = skill_domain.SkillContents( state_domain.SubtitledHtml('1', '<p>Skill Explanation</p>'), [ state_domain.SubtitledHtml('2', '<p>Example 1</p>'), state_domain.SubtitledHtml('3', '<p>Example 2</p>') ], state_domain.RecordedVoiceovers.from_dict( {'voiceovers_mapping': { '1': {}, '2': {}, '3': {} }}), state_domain.WrittenTranslations.from_dict( {'translations_mapping': { '1': {}, '2': {}, '3': {} }})) self.skill_contents_1 = skill_domain.SkillContents( state_domain.SubtitledHtml('1', '<p>Skill Explanation 1</p>'), [ state_domain.SubtitledHtml('2', '<p>Example 3</p>'), state_domain.SubtitledHtml('3', '<p>Example 4</p>') ], state_domain.RecordedVoiceovers.from_dict( {'voiceovers_mapping': { '1': {}, '2': {}, '3': {} }}), state_domain.WrittenTranslations.from_dict( {'translations_mapping': { '1': {}, '2': {}, '3': {} }})) self.admin = user_services.UserActionsInfo(self.admin_id) self.skill_id = skill_services.get_new_skill_id() self.save_new_skill(self.skill_id, self.admin_id, 'Description', skill_contents=self.skill_contents) self.skill_id_1 = skill_services.get_new_skill_id() self.save_new_skill(self.skill_id_1, self.admin_id, 'Description', skill_contents=self.skill_contents_1) self.skill_id_2 = skill_services.get_new_skill_id()
def test_no_action_is_performed_for_deleted_exploration(self): """Test that no action is performed on deleted explorations.""" exploration = exp_domain.Exploration.create_default_exploration( self.VALID_EXP_ID, title='title', category='category') exploration.add_states(['State1']) state1 = exploration.states['State1'] state1.update_interaction_id('MultipleChoiceInput') customization_args_dict = { 'choices': {'value': [{ 'html': '<p>This is value1 for MultipleChoiceInput</p>', 'content_id': 'ca_choices_0' }, { 'html': '<p>This is value2 for MultipleChoiceInput</p>', 'content_id': 'ca_choices_1' }]}, 'showChoicesInShuffledOrder': {'value': True} } state_answer_group_list = [state_domain.AnswerGroup( state_domain.Outcome( 'State1', state_domain.SubtitledHtml( 'feedback', '<p>Outcome for state2</p>'), False, [], None, None), [ state_domain.RuleSpec('Equals', {'x': '0'}), state_domain.RuleSpec( 'Equals', {'x': '9007199254740991'}) ], [], None )] state1.update_interaction_customization_args(customization_args_dict) state1.update_next_content_id_index(2) state1.update_interaction_answer_groups(state_answer_group_list) exp_services.save_new_exploration(self.albert_id, exploration) exp_services.delete_exploration(self.albert_id, self.VALID_EXP_ID) run_job_for_deleted_exp( self, interaction_jobs_one_off.MultipleChoiceInteractionOneOffJob)
def test_migrate_rubrics_to_latest_schema(self): skill_services.create_new_skill_rights('skill_id', 'user_id_admin') commit_cmd = skill_domain.SkillChange({ 'cmd': skill_domain.CMD_CREATE_NEW }) explanation_content_id = feconf.DEFAULT_SKILL_EXPLANATION_CONTENT_ID skill_contents = skill_domain.SkillContents( state_domain.SubtitledHtml( explanation_content_id, feconf.DEFAULT_SKILL_EXPLANATION), [], state_domain.RecordedVoiceovers.from_dict({ 'voiceovers_mapping': { explanation_content_id: {} } }), state_domain.WrittenTranslations.from_dict({ 'translations_mapping': { explanation_content_id: {} } })) rubric = skill_domain.Rubric( constants.SKILL_DIFFICULTIES[0], '<p>Explanation</p>') model = skill_models.SkillModel( id='skill_id', description='description', language_code='en', misconceptions=[], rubrics=[rubric.to_dict()], skill_contents=skill_contents.to_dict(), next_misconception_id=1, misconceptions_schema_version=1, rubric_schema_version=1, skill_contents_schema_version=1, all_questions_merged=False ) commit_cmd_dicts = [commit_cmd.to_dict()] model.commit( 'user_id_admin', 'skill model created', commit_cmd_dicts) swap_skill_object = self.swap(skill_domain, 'Skill', MockSkillObject) current_schema_version_swap = self.swap( feconf, 'CURRENT_RUBRIC_SCHEMA_VERSION', 2) with swap_skill_object, current_schema_version_swap: skill = skill_services.get_skill_from_model(model) self.assertEqual(skill.rubric_schema_version, 2)
def setUp(self): super(SuggestionMigrationOneOffJobTest, self).setUp() self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME) self.signup(self.EDITOR_EMAIL, self.EDITOR_USERNAME) self.signup(self.AUTHOR_EMAIL, 'author') self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) self.editor_id = self.get_user_id_from_email(self.EDITOR_EMAIL) self.author_id = self.get_user_id_from_email(self.AUTHOR_EMAIL) self.editor = user_services.UserActionsInfo(self.editor_id) # Login and create exploration and suggestions. self.login(self.EDITOR_EMAIL) # Create exploration. self.save_new_valid_exploration(self.EXP_ID, self.editor_id, title='Exploration for suggestions', category='Algebra', objective='Test a suggestion.') exploration = exp_services.get_exploration_by_id(self.EXP_ID) init_state = exploration.states[exploration.init_state_name] init_interaction = init_state.interaction init_interaction.default_outcome.dest = exploration.init_state_name self.old_content = state_domain.SubtitledHtml('content', 'old content').to_dict() exp_services.update_exploration(self.editor_id, self.EXP_ID, [ exp_domain.ExplorationChange({ 'cmd': exp_domain.CMD_ADD_STATE, 'state_name': 'State 1', }), exp_domain.ExplorationChange({ 'cmd': exp_domain.CMD_EDIT_STATE_PROPERTY, 'state_name': 'State 1', 'property_name': exp_domain.STATE_PROPERTY_CONTENT, 'new_value': self.old_content }) ], 'Add state name') rights_manager.publish_exploration(self.editor, self.EXP_ID) rights_manager.assign_role_for_exploration(self.editor, self.EXP_ID, self.owner_id, rights_manager.ROLE_EDITOR)
def test_feedback_threads_with_suggestions(self): with self.swap(constants, 'ENABLE_GENERALIZED_FEEDBACK_THREADS', False): new_content = state_domain.SubtitledHtml( 'content', 'new content html').to_dict() change_cmd = { 'cmd': exp_domain.CMD_EDIT_STATE_PROPERTY, 'property_name': exp_domain.STATE_PROPERTY_CONTENT, 'state_name': 'State 1', 'new_value': new_content } suggestion_services.create_suggestion( suggestion_models.SUGGESTION_TYPE_EDIT_STATE_CONTENT, suggestion_models.TARGET_TYPE_EXPLORATION, self.EXP_ID, 1, self.user_id, change_cmd, 'sample description', None) response = self.get_json( '%s/%s' % ( feconf.FEEDBACK_THREADLIST_URL_PREFIX, self.EXP_ID)) self.assertEqual(response['feedback_thread_dicts'], []) expected_thread_dict = { 'original_author_username': self.USER_USERNAME, 'status': feedback_models.STATUS_CHOICES_OPEN, 'subject': 'sample description' } self.assertDictContainsSubset( expected_thread_dict, response['suggestion_thread_dicts'][0]) thread_id = ( response['suggestion_thread_dicts'][0]['thread_id']) response = self.get_json( '%s/%s' % ( feconf.FEEDBACK_THREAD_URL_PREFIX, thread_id)) expected_suggestion_dict = { 'suggestion_type': ( suggestion_models .SUGGESTION_TYPE_EDIT_STATE_CONTENT), 'target_type': ( suggestion_models.TARGET_TYPE_EXPLORATION), 'target_id': self.EXP_ID, 'status': suggestion_models.STATUS_IN_REVIEW, 'author_name': self.USER_USERNAME } self.assertDictContainsSubset( expected_suggestion_dict, response['suggestion'])
def test_skill_creation_in_invalid_topic(self): self.login(self.CURRICULUM_ADMIN_EMAIL) csrf_token = self.get_new_csrf_token() payload = { 'description': 'Skill Description', 'linked_topic_ids': ['topic'], 'rubrics': [], 'explanation_dict': state_domain.SubtitledHtml( '1', '<p>Explanation</p>').to_dict(), 'thumbnail_filename': 'image.svg' } json_response = self.post_json( self.url, payload, csrf_token=csrf_token, expected_status_int=400, upload_files=(( 'image', 'unused_filename', self.original_image_content),)) self.assertEqual(json_response['status_code'], 400) self.logout()
def test_solution_validation(self): """Test validation of state solution.""" exploration = exp_domain.Exploration.create_default_exploration('eid') exploration.objective = 'Objective' init_state = exploration.states[exploration.init_state_name] init_state.update_interaction_id('TextInput') exploration.validate() # Solution should be set to None as default. self.assertEqual(init_state.interaction.solution, None) init_state.add_hint(state_domain.SubtitledHtml('hint_1', {})) solution = { 'answer_is_exclusive': False, 'correct_answer': [0, 0], 'explanation': { 'content_id': 'solution', 'html': 'hello_world is a string' } } # Object type of answer must match that of correct_answer. with self.assertRaises(AssertionError): init_state.interaction.solution = (state_domain.Solution.from_dict( init_state.interaction.id, solution)) solution = { 'answer_is_exclusive': False, 'correct_answer': 'hello_world!', 'explanation': { 'content_id': 'solution', 'html': 'hello_world is a string' } } init_state.interaction.solution = (state_domain.Solution.from_dict( init_state.interaction.id, solution)) init_state.update_content_ids_to_audio_translations({ 'content': {}, 'default_outcome': {}, 'hint_1': {}, 'solution': {} }) exploration.validate()
def test_get_concept_cards(self): json_response = self.get_json( '%s/%s,%s' % ( feconf.CONCEPT_CARD_DATA_URL_PREFIX, self.skill_id, self.skill_id_1) ) self.assertEqual(2, len(json_response['concept_card_dicts'])) self.assertEqual( '<p>Skill Explanation</p>', json_response['concept_card_dicts'][0]['explanation']['html']) self.assertEqual( [skill_domain.WorkedExample( state_domain.SubtitledHtml( '2', '<p>Example Question 1</p>'), state_domain.SubtitledHtml( '3', '<p>Example Explanation 1</p>') ).to_dict(), skill_domain.WorkedExample( state_domain.SubtitledHtml( '4', '<p>Example Question 2</p>'), state_domain.SubtitledHtml( '5', '<p>Example Explanation 2</p>') ).to_dict()], json_response['concept_card_dicts'][0]['worked_examples']) self.assertEqual( '<p>Skill Explanation 1</p>', json_response['concept_card_dicts'][1]['explanation']['html']) self.assertEqual( [skill_domain.WorkedExample( state_domain.SubtitledHtml( '2', '<p>Example Question 1</p>'), state_domain.SubtitledHtml( '3', '<p>Example Explanation 1</p>') ).to_dict(), skill_domain.WorkedExample( state_domain.SubtitledHtml( '4', '<p>Example Question 2</p>'), state_domain.SubtitledHtml( '5', '<p>Example Explanation 2</p>') ).to_dict()], json_response['concept_card_dicts'][1]['worked_examples'])