def test_camelcase_to_snakecase(self): """Test camelcase_to_hyphenated method.""" test_cases = [ ('AbcDef', 'abc_def'), ('Abc', 'abc'), ('abc_def', 'abc_def'), ('Abc012Def345', 'abc012_def345'), ('abcDef', 'abc_def'), ('abc-def', 'abc-def'), ] for test_case in test_cases: self.assertEqual(utils.camelcase_to_snakecase(test_case[0]), test_case[1])
def test_default_interactions_are_valid(self): """Test that the default interactions are valid.""" all_interaction_ids = ( interaction_registry.Registry.get_all_interaction_ids()) for interaction_id in all_interaction_ids: # Check that the interaction id is valid. self.assertTrue(self._is_camel_cased(interaction_id)) # Check that the interaction directory exists. interaction_dir = os.path.join( feconf.INTERACTIONS_DIR, interaction_id) self.assertTrue(os.path.isdir(interaction_dir)) # The interaction directory should contain the following files: # Required: # * A python file called {InteractionName}.py. # * An __init__.py file used to import the Python file. # * A TypeScript file called {InteractionName}.ts. # * A directory name 'directives' containing TS and HTML files # for directives # * A directory named 'static' containing at least a .png file. # Optional: # * A JS file called protractor.js. interaction_dir_contents = ( self._listdir_omit_ignored(interaction_dir)) interaction_dir_optional_dirs_and_files_count = 0 try: self.assertTrue(os.path.isfile(os.path.join( interaction_dir, 'protractor.js'))) interaction_dir_optional_dirs_and_files_count += 1 except Exception: pass try: self.assertTrue(os.path.isfile(os.path.join( interaction_dir, '%sPredictionService.ts' % interaction_id))) interaction_dir_optional_dirs_and_files_count += 1 except Exception: pass try: self.assertTrue(os.path.isfile(os.path.join( interaction_dir, '%sPredictionServiceSpec.ts' % interaction_id))) interaction_dir_optional_dirs_and_files_count += 1 except Exception: pass self.assertEqual( interaction_dir_optional_dirs_and_files_count + 5, len(interaction_dir_contents) ) py_file = os.path.join(interaction_dir, '%s.py' % interaction_id) ts_file = os.path.join( interaction_dir, '%s.ts' % interaction_id) self.assertTrue(os.path.isfile(py_file)) self.assertTrue(os.path.isfile(ts_file)) # Check that __init__.py file exists. init_file = os.path.join(interaction_dir, '__init__.py') self.assertTrue(os.path.isfile(init_file)) # Check that the directives subdirectory exists. directives_dir = os.path.join( interaction_dir, 'directives') self.assertTrue(os.path.isdir(directives_dir)) # The directives directory should contain the following files: # Required: # * A TS file called # OppiaInteractive{InteractionName}Directive.ts. # * A TS file called OppiaResponse{InteractionName}Directive.ts. # * A TS file called # OppiaShortResponse{InteractionName}Directive.ts. # * A TS file called {InteractionName}RulesService.ts. # * A TS file called {InteractionName}ValidationService.ts. # * A HTML file called # {InteractionName}_interaction_directive.html. # * A HTML file called # {InteractionName}_response_directive.html. # * A HTML file called # {InteractionName}_short_response_directive.html. # Optional: # * A TS file called {InteractionName}ValidationServiceSpecs.ts. # * A TS file called {InteractionName}RulesServiceSpecs.ts. snakecase_interaction_id = ( utils.camelcase_to_snakecase(interaction_id)) interaction_directive_ts_file = os.path.join( directives_dir, 'OppiaInteractive%sDirective.ts' % ( interaction_id)) response_directive_ts_file = os.path.join( directives_dir, 'OppiaResponse%sDirective.ts' % interaction_id) short_response_directive_ts_file = os.path.join( directives_dir, 'OppiaShortResponse%sDirective.ts' % ( interaction_id)) rules_service_ts_file = os.path.join( directives_dir, '%sRulesService.ts' % interaction_id) validation_service_ts_file = os.path.join( directives_dir, '%sValidationService.ts' % interaction_id) interaction_directive_html = os.path.join( directives_dir, '%s_interaction_directive.html' % snakecase_interaction_id) response_directive_html = os.path.join( directives_dir, '%s_response_directive.html' % snakecase_interaction_id) short_response_directive_html = os.path.join( directives_dir, '%s_short_response_directive.html' % snakecase_interaction_id) self.assertTrue(os.path.isfile(interaction_directive_ts_file)) self.assertTrue(os.path.isfile(response_directive_ts_file)) self.assertTrue(os.path.isfile(short_response_directive_ts_file)) self.assertTrue(os.path.isfile(rules_service_ts_file)) self.assertTrue(os.path.isfile(validation_service_ts_file)) self.assertTrue(os.path.isfile(interaction_directive_html)) self.assertTrue(os.path.isfile(response_directive_html)) self.assertTrue(os.path.isfile(short_response_directive_html)) # Check that the PNG thumbnail image has the correct dimensions. static_dir = os.path.join(interaction_dir, 'static') self.assertTrue(os.path.isdir(static_dir)) png_file = os.path.join( interaction_dir, 'static', '%s.png' % interaction_id) self.assertTrue(os.path.isfile(png_file)) with python_utils.open_file(png_file, 'rb', encoding=None) as f: img_data = f.read() width, height = struct.unpack('>LL', img_data[16:24]) self.assertEqual(int(width), INTERACTION_THUMBNAIL_WIDTH_PX) self.assertEqual(int(height), INTERACTION_THUMBNAIL_HEIGHT_PX) interaction_directive_ts_file_content = utils.get_file_contents( interaction_directive_ts_file) response_directive_ts_file_content = utils.get_file_contents( response_directive_ts_file) short_response_directive_ts_file_content = utils.get_file_contents( short_response_directive_ts_file) ts_file_content = utils.get_file_contents(ts_file) rules_service_ts_file_content = utils.get_file_contents( rules_service_ts_file) validation_service_ts_file_content = utils.get_file_contents( validation_service_ts_file) self.assertIn( 'oppiaInteractive%s' % interaction_id, interaction_directive_ts_file_content) self.assertIn( 'oppiaResponse%s' % interaction_id, response_directive_ts_file_content) self.assertIn( 'oppiaShortResponse%s' % interaction_id, short_response_directive_ts_file_content) self.assertIn( '%sRulesService' % ( interaction_id[0] + interaction_id[1:]), rules_service_ts_file_content) self.assertIn( '%sValidationService' % interaction_id, validation_service_ts_file_content) # Check that the html template includes js script for the # interaction. self.assertIn( 'OppiaInteractive%sDirective.ts' % interaction_id, ts_file_content) self.assertIn( 'OppiaResponse%sDirective.ts' % interaction_id, ts_file_content) self.assertIn( 'OppiaShortResponse%sDirective.ts' % interaction_id, ts_file_content) self.assertIn( '%sRulesService.ts' % interaction_id, ts_file_content) self.assertIn( '%sValidationService.ts' % interaction_id, ts_file_content) self.assertNotIn('<script>', interaction_directive_ts_file_content) self.assertNotIn('</script>', interaction_directive_ts_file_content) self.assertNotIn('<script>', response_directive_ts_file_content) self.assertNotIn('</script>', response_directive_ts_file_content) self.assertNotIn( '<script>', short_response_directive_ts_file_content) self.assertNotIn( '</script>', short_response_directive_ts_file_content) self.assertNotIn('<script>', rules_service_ts_file_content) self.assertNotIn('</script>', rules_service_ts_file_content) self.assertNotIn('<script>', validation_service_ts_file_content) self.assertNotIn('</script>', validation_service_ts_file_content) interaction = interaction_registry.Registry.get_interaction_by_id( interaction_id) # Check that the specified interaction id is the same as the class # name. self.assertTrue(interaction_id, msg=interaction.__class__.__name__) # Check that the configuration file contains the correct # top-level keys, and that these keys have the correct types. for item, item_type in _INTERACTION_CONFIG_SCHEMA: self.assertTrue(isinstance( getattr(interaction, item), item_type)) if item_type == python_utils.BASESTRING: self.assertTrue(getattr(interaction, item)) self.assertIn(interaction.display_mode, base.ALLOWED_DISPLAY_MODES) if interaction.is_linear or interaction.is_terminal: self.assertIsNone(interaction.answer_type) else: # Check that the answer_type corresponds to a valid object # class. obj_services.Registry.get_object_class_by_type( interaction.answer_type) self._validate_customization_arg_specs( interaction._customization_arg_specs) # pylint: disable=protected-access self._validate_dependencies(interaction.dependency_ids) answer_visualization_specs = ( interaction.answer_visualization_specs) self._validate_answer_visualization_specs( answer_visualization_specs) answer_visualizations = interaction.answer_visualizations for ind, visualization in enumerate(answer_visualizations): self.assertEqual( visualization.id, answer_visualization_specs[ind]['id']) self.assertEqual( visualization.calculation_id, answer_visualization_specs[ind]['calculation_id']) self.assertEqual( visualization.options, answer_visualization_specs[ind]['options']) # Check that the derived visualization is valid. visualization.validate() # Check that supplemental interactions have instructions, and # inline ones do not. if interaction.display_mode == base.DISPLAY_MODE_INLINE: self.assertIsNone(interaction.instructions) self.assertIsNone(interaction.narrow_instructions) else: self.assertTrue( isinstance( interaction.instructions, python_utils.BASESTRING)) self.assertIsNotNone(interaction.instructions) self.assertIsNotNone(interaction.narrow_instructions) # Check that terminal interactions are not linear. if interaction.is_terminal: self.assertFalse(interaction.is_linear) # Check that only linear interactions have a # default_outcome_heading property. if interaction.is_linear: self.assertTrue( isinstance( interaction.default_outcome_heading, python_utils.BASESTRING) and interaction.default_outcome_heading) else: self.assertIsNone(interaction.default_outcome_heading) # Check that interactions that can have solution cannot be linear. if interaction.can_have_solution: self.assertFalse(interaction.is_linear) default_object_values = obj_services.get_default_object_values() # Check that the rules for this interaction have object editor # templates and default values. for rule_name in list(interaction.rules_dict.keys()): param_list = interaction.get_rule_param_list(rule_name) for (_, param_obj_cls) in param_list: # TODO(sll): Get rid of these special cases. if param_obj_cls.__name__ in [ 'NonnegativeInt', 'ListOfCodeEvaluation', 'ListOfCoordTwoDim', 'ListOfGraph', 'SetOfNormalizedString']: continue # Check that the rule has a default value. self.assertIn( param_obj_cls.__name__, default_object_values)