/
githubmirror
/
oppia
Обзор
Документация
Войти
/
githubmirror
/
oppia
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
develop
core/domain/learner_goals_services_test.py
399 строк
14 KB
Gabriel Fuentes
Black formatter staging (#23456)
05 окт 2025, 06:15
Не верифицирован
05 окт 2025, 06:15
62ec95a
Код
Авторство
О чём код?
# coding: utf-8 # # Copyright 2017 The Oppia Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS-IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Tests for learner goals services.""" from __future__ import annotations from core import feconf from core.constants import constants from core.domain import ( learner_goals_services, learner_progress_services, topic_domain, topic_services, ) from core.platform import models from core.tests import test_utils from typing import Final, List MYPY = False if MYPY: # pragma: no cover from mypy_imports import user_models (user_models,) = models.Registry.import_models([models.Names.USER]) MAX_CURRENT_GOALS_COUNT: Final = feconf.MAX_CURRENT_GOALS_COUNT class LearnerGoalsTests(test_utils.GenericTestBase): """Test the services related to learner goals services.""" TOPIC_ID_1: Final = 'Topic_id_1' TOPIC_NAME_1: Final = 'Topic name 1' TOPIC_ID_2: Final = 'Topic_id_2' TOPIC_NAME_2: Final = 'Topic name 2' TOPIC_ID_3: Final = 'Topic_id_3' TOPIC_NAME_3: Final = 'Topic name 3' TOPIC_ID_4: Final = 'Topic_id_4' TOPIC_NAME_4: Final = 'Topic name 4' subtopic_1 = topic_domain.Subtopic( 0, 'Title 1', ['skill_id_1'], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 21131, 'dummy-subtopic-zero', ) subtopic_2 = topic_domain.Subtopic( 0, 'Title 1', ['skill_id_1'], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 21131, 'dummy-subtopic-zero', ) subtopic_3 = topic_domain.Subtopic( 0, 'Title 1', ['skill_id_1'], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 21131, 'dummy-subtopic-zero', ) subtopic_4 = topic_domain.Subtopic( 0, 'Title 1', ['skill_id_1'], 'image.svg', constants.ALLOWED_THUMBNAIL_BG_COLORS['subtopic'][0], 21131, 'dummy-subtopic-zero', ) def setUp(self) -> None: super().setUp() self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME) self.signup(self.VIEWER_EMAIL, self.VIEWER_USERNAME) self.signup(self.CURRICULUM_ADMIN_EMAIL, self.CURRICULUM_ADMIN_USERNAME) self.viewer_id = self.get_user_id_from_email(self.VIEWER_EMAIL) self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) self.curriculum_admin_id = self.get_user_id_from_email( self.CURRICULUM_ADMIN_EMAIL ) self.set_curriculum_admins([self.CURRICULUM_ADMIN_USERNAME]) # Save the topics. self.save_new_topic( self.TOPIC_ID_1, self.owner_id, name=self.TOPIC_NAME_1, url_fragment='topic-one', description='A new topic', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[], subtopics=[self.subtopic_1], next_subtopic_id=1, ) topic_services.publish_topic(self.TOPIC_ID_1, self.curriculum_admin_id) self.save_new_topic( self.TOPIC_ID_2, self.owner_id, name=self.TOPIC_NAME_2, url_fragment='topic-two', description='A new topic', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[], subtopics=[self.subtopic_2], next_subtopic_id=1, ) topic_services.publish_topic(self.TOPIC_ID_2, self.curriculum_admin_id) self.save_new_topic( self.TOPIC_ID_3, self.owner_id, name=self.TOPIC_NAME_3, url_fragment='topic-three', description='A new topic', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[], subtopics=[self.subtopic_3], next_subtopic_id=1, ) topic_services.publish_topic(self.TOPIC_ID_3, self.curriculum_admin_id) self.save_new_topic( self.TOPIC_ID_4, self.owner_id, name=self.TOPIC_NAME_4, url_fragment='topic-four', description='A new topic', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[], subtopics=[self.subtopic_4], next_subtopic_id=1, ) topic_services.publish_topic(self.TOPIC_ID_4, self.curriculum_admin_id) def _get_all_topic_ids_to_learn(self, user_id: str) -> List[str]: """Returns the list of all the topic ids to learn corresponding to the given user id. """ learner_goals_model = user_models.LearnerGoalsModel.get( user_id, strict=False ) # TODO(#15621): The explicit declaration of type for ndb properties # should be removed. Currently, these ndb properties are annotated with # Any return type. Once we have proper return type we can remove this. if learner_goals_model: topic_ids: List[str] = learner_goals_model.topic_ids_to_learn return topic_ids else: return [] def test_single_topic_is_added_correctly_to_learn(self) -> None: # Test adding a single topic_id to learn. self.assertEqual(self._get_all_topic_ids_to_learn(self.viewer_id), []) learner_progress_services.validate_and_add_topic_to_learn_goal( self.viewer_id, self.TOPIC_ID_1 ) self.assertEqual( self._get_all_topic_ids_to_learn(self.viewer_id), [self.TOPIC_ID_1] ) def test_multiple_topics_are_added_correctly_to_learn(self) -> None: # Test adding two topics to the learn. self.assertEqual(self._get_all_topic_ids_to_learn(self.viewer_id), []) learner_progress_services.validate_and_add_topic_to_learn_goal( self.viewer_id, self.TOPIC_ID_1 ) self.assertEqual( self._get_all_topic_ids_to_learn(self.viewer_id), [self.TOPIC_ID_1] ) learner_progress_services.validate_and_add_topic_to_learn_goal( self.viewer_id, self.TOPIC_ID_2 ) self.assertEqual( self._get_all_topic_ids_to_learn(self.viewer_id), [self.TOPIC_ID_1, self.TOPIC_ID_2], ) def test_adding_exisiting_topic_is_not_added_again(self) -> None: # Test adding the topic_id if it is already in # learner_goals.topic_id. learner_progress_services.validate_and_add_topic_to_learn_goal( self.viewer_id, self.TOPIC_ID_1 ) learner_progress_services.validate_and_add_topic_to_learn_goal( self.viewer_id, self.TOPIC_ID_2 ) self.assertEqual( self._get_all_topic_ids_to_learn(self.viewer_id), [self.TOPIC_ID_1, self.TOPIC_ID_2], ) with self.assertRaisesRegex( Exception, 'The topic id Topic_id_1 is already present in the learner goals', ): learner_progress_services.validate_and_add_topic_to_learn_goal( self.viewer_id, self.TOPIC_ID_1 ) def test_completed_topic_is_not_added_to_learner_goals(self) -> None: learner_progress_services.validate_and_add_topic_to_learn_goal( self.viewer_id, self.TOPIC_ID_1 ) self.assertEqual( self._get_all_topic_ids_to_learn(self.viewer_id), [self.TOPIC_ID_1] ) learner_progress_services.mark_topic_as_learnt( self.viewer_id, self.TOPIC_ID_2 ) # Test that the topic added to the in the learnt list doesn't get # added to the learner goals. self.assertEqual( self._get_all_topic_ids_to_learn(self.viewer_id), [self.TOPIC_ID_1] ) def test_number_of_topics_cannot_exceed_max(self) -> None: # Add MAX_CURRENT_GOALS_COUNT topics. topic_ids = [ 'SAMPLE_TOPIC_ID_%s' % index for index in (range(0, MAX_CURRENT_GOALS_COUNT)) ] for topic_id in topic_ids: learner_progress_services.validate_and_add_topic_to_learn_goal( self.viewer_id, topic_id ) self.assertEqual( self._get_all_topic_ids_to_learn(self.viewer_id), topic_ids ) # Now if we try to add another topic at the end of the list, # it shouldn't be added as the list length would exceed # MAX_CURRENT_GOALS_COUNT. learner_goals_services.mark_topic_to_learn( self.viewer_id, 'SAMPLE_TOPIC_ID_MAX' ) self.assertEqual( self._get_all_topic_ids_to_learn(self.viewer_id), topic_ids ) def test_remove_topic_from_learner_goals(self) -> None: self.assertEqual(self._get_all_topic_ids_to_learn(self.viewer_id), []) # Add topic to learner goals. learner_goals_services.mark_topic_to_learn( self.viewer_id, self.TOPIC_ID_1 ) learner_goals_services.mark_topic_to_learn( self.viewer_id, self.TOPIC_ID_2 ) self.assertEqual( self._get_all_topic_ids_to_learn(self.viewer_id), [self.TOPIC_ID_1, self.TOPIC_ID_2], ) # Removing a topic. learner_goals_services.remove_topics_from_learn_goal( self.viewer_id, [self.TOPIC_ID_1] ) self.assertEqual( self._get_all_topic_ids_to_learn(self.viewer_id), [self.TOPIC_ID_2] ) # Removing the same topic raises error. with self.assertRaisesRegex( Exception, 'The topic id Topic_id_1 is not present in LearnerGoalsModel', ): learner_goals_services.remove_topics_from_learn_goal( self.viewer_id, [self.TOPIC_ID_1] ) # Removing the second topic. learner_goals_services.remove_topics_from_learn_goal( self.viewer_id, [self.TOPIC_ID_2] ) self.assertEqual(self._get_all_topic_ids_to_learn(self.viewer_id), []) def test_get_all_topic_ids_in_learn(self) -> None: self.assertEqual( learner_goals_services.get_all_topic_ids_to_learn(self.viewer_id), [], ) # Add an topic to the learner goals. learner_goals_services.mark_topic_to_learn( self.viewer_id, self.TOPIC_ID_1 ) self.assertEqual( learner_goals_services.get_all_topic_ids_to_learn(self.viewer_id), [self.TOPIC_ID_1], ) # Add another topic. learner_goals_services.mark_topic_to_learn( self.viewer_id, self.TOPIC_ID_2 ) self.assertEqual( learner_goals_services.get_all_topic_ids_to_learn(self.viewer_id), [self.TOPIC_ID_1, self.TOPIC_ID_2], ) def test_remove_topics_from_learn_goal_executed_correctly(self) -> None: self.assertEqual(self._get_all_topic_ids_to_learn(self.viewer_id), []) # Add topics to learner goals. learner_goals_services.mark_topic_to_learn( self.viewer_id, self.TOPIC_ID_1 ) learner_goals_services.mark_topic_to_learn( self.viewer_id, self.TOPIC_ID_2 ) self.assertEqual( self._get_all_topic_ids_to_learn(self.viewer_id), [self.TOPIC_ID_1, self.TOPIC_ID_2], ) # Remove a topic from learner goals. learner_goals_services.remove_topics_from_learn_goal( self.viewer_id, [self.TOPIC_ID_1] ) self.assertEqual( self._get_all_topic_ids_to_learn(self.viewer_id), [self.TOPIC_ID_2] ) # Check if the removed topic is not present in the learner goals. learner_goals = learner_goals_services.get_all_topic_ids_to_learn( self.viewer_id ) self.assertNotIn(self.TOPIC_ID_1, learner_goals) # Check if the remaining topic is still present in the learner goals. self.assertIn(self.TOPIC_ID_2, learner_goals) # Remove the remaining topic from learner goals. learner_goals_services.remove_topics_from_learn_goal( self.viewer_id, [self.TOPIC_ID_2] ) self.assertEqual(self._get_all_topic_ids_to_learn(self.viewer_id), []) # Check if both topics are not present in the learner goals. learner_goals = learner_goals_services.get_all_topic_ids_to_learn( self.viewer_id ) self.assertNotIn(self.TOPIC_ID_1, learner_goals) self.assertNotIn(self.TOPIC_ID_2, learner_goals) def test_remove_topics_when_learner_goals_model_does_not_exist( self, ) -> None: non_existent_user_id = 'non_existent_user_id' self.assertIsNone( user_models.LearnerGoalsModel.get( non_existent_user_id, strict=False ) ) # Call the function directly. It should not result in an error. # If an error occurs, the test case will fail automatically. learner_goals_services.remove_topics_from_learn_goal( non_existent_user_id, [self.TOPIC_ID_1] ) # Check the state of learner_goals to make sure nothing unexpected # has happened. learner_goals = learner_goals_services.get_all_topic_ids_to_learn( non_existent_user_id ) self.assertEqual(learner_goals, [])