def is_tutorial_default_message(default_message, languages=None): """Validates the specified set of default messages. Args: default_message (dict): A set of default messages. languages (list): A list of available languages. Returns: <bool, str|None>: A pair containing the value True if the specified message set is valid, False otherwise; and an error message in case the set is invalid. Raises: TypeError: If the default_message argument is not a dictionary, or if the languages argument is not a list or NoneType. """ check_arg_type(is_tutorial_default_message, "default_message", default_message, dict) check_arg_type(is_tutorial_default_message, "languages", languages, (list, type(None))) unexpected_keys = find_unexpected_keys(default_message, is_tutorial_configuration.DEFAULT_MESSAGE_FIELDS) if unexpected_keys: message = "The tutorial's 'default-message' contains the following unrecognized fields: '{}'." return (False, message.format("', '".join(unexpected_keys))) for key, message in default_message.iteritems(): if not is_configuration_string(message, languages): return (False, "The tutorial's default message field '{}' is invalid. A message must be a non-empty or normalized string.".format(key)) return (True, None)
def __is_multiple_option_input(question_input, languages=None): unexpected_keys = find_unexpected_keys(question_input, __is_multiple_option_input.FIELDS) if unexpected_keys: message = "The multiple-option input configuration contains the following unrecognized fields: '{}'." return (False, message.format("', '".join(unexpected_keys))) for key in ["enable-multiple-choices", "enable-other-option", "enable-illustrations"]: field = question_input.get(key) if field is not None and not isinstance(field, bool): return (False, "The '{}' field must be a boolean value.".format(key)) options = question_input.get("options") if options is not None: enable_illustrations = question_input.get("enable-illustrations", False) if not isinstance(options, list) or len(options) < 1: return (False, "The 'options' field must be a non-empty list.") else: for option in options: label = option.get("label") error = (False, "An option label must be a non-empty or normalized string.") try: if label is None or not is_configuration_string(label, languages): return error except TypeError: return error value = option.get("value") if value is None or not isinstance(value, basestring): return (False, "An option value must be a string.") # If the 'enable-illustrations' flag is set to True, validate illustrations. illustration = option.get("illustration") if enable_illustrations else None if illustration is not None: missing = [k for k in illustration.keys() if k not in __is_multiple_option_input.ILLUSTRATION_FIELDS or illustration[k] is None] if missing: missing = "', '".join(missing) return (False, "The illustration is missing the following fields: '{}'.".format(missing)) for key in __is_multiple_option_input.ILLUSTRATION_FIELDS: try: field = illustration.get(key) if is_empty_string(field): return (False, "An illustration's '{}' field must be a non-empty string.".format(key)) except: return (False, "An illustration's '{}' field must be a string.".format(key)) else: return (False, "The 'options' field must be a non-empty list.") return (True, None)
def __is_text_input(question_input, languages=None): """Validates the specified text input configuration. Args: question_input (dict): An input configuration to validate. languages (list): A list of languages that the normalized string dictionary must contain, where each item of the list is a language code. Returns: <bool, str|None>: A pair containing the value True if the specified configuration is valid, False otherwise; as well as an error message in case it is invalid. """ unexpected_keys = find_unexpected_keys(question_input, __is_text_input.FIELDS) if unexpected_keys: message = "The text input configuration contains the following unrecognized fields: '{}'." return (False, message.format("', '".join(unexpected_keys))) placeholder = question_input.get("placeholder") if placeholder is not None: error = (False, "A placeholder must be a non-empty or normalized string.") try: if not is_configuration_string(placeholder, languages): return error except TypeError: return error enable_long_text = question_input.get("enable-long-text") if enable_long_text is not None and not isinstance(enable_long_text, bool): return (False, "The 'enable-long-text' field must be a boolean value.") min_length = question_input.get("min-length") if min_length is not None: if not isinstance(min_length, int): return (False, "The 'min-length' field must be an integer value.") elif min_length < 0: return (False, "The 'min-length' must be a positive integer.") max_length = question_input.get("max-length") if max_length is not None: if not isinstance(max_length, int): return (False, "The 'max-length' field must be an integer value.") elif max_length < 0: return (False, "The 'min-length' must be a positive integer.") elif min_length is not None and max_length < min_length: return (False, "The 'max-length' must be greater than or equal to the 'min-length'.") return (True, None)
def is_question_help(question_help, languages=None): """Validates the specified question help. A help is a non-empty or normalized string. Args: help (str|dict): The help to validate. languages (list): A list of languages that the normalized string dictionary must contain, where each item of the list is a language code. Note that this parameter is used if and only if the help is a normalized string. Returns: <bool, str|None>: A pair containing the value True if the help is valid, False otherwise; as well as an error message in case it is invalid. Raises: TypeError: If the question_help argument is not a string or dictionary, or if languages is not a list or NoneType. """ if not is_configuration_string(question_help, languages): return (False, "A question help field must be a non-empty or normalized string.") return (True, None)
def is_messages(assertion_messages): check_arg_type(is_messages, "assertion_messages", assertion_messages, dict) if any(not is_configuration_string(m, languages) for m in assertion_messages.itervalues()): return (False, "A tutorial subject assertion message must be a non-empty or normalized string.") return (True, None)
def test_illegal_configuration_strings(self): self.assertRaises(TypeError, helper.is_configuration_string, None) self.assertRaises(TypeError, helper.is_configuration_string, 42) self.assertRaises(TypeError, helper.is_configuration_string, []) self.assertRaises(TypeError, helper.is_configuration_string, {}, 42) self.assertRaises(TypeError, helper.is_configuration_string, {}, ("en", "fr")) self.assertRaises(TypeError, helper.is_configuration_string, {}, "") self.assertFalse(helper.is_configuration_string({}), "Empty dictionary") self.assertFalse(helper.is_configuration_string({"en": ""}), "Empty string with a valid language code") self.assertFalse(helper.is_configuration_string({"en": None}), "Valid language code with non-string (None) value") self.assertFalse(helper.is_configuration_string({"en": 32}), "Valid language code with non-string (int) value") self.assertFalse(helper.is_configuration_string({"en": {}}), "Valid language code with non-string (dict) value") self.assertFalse( helper.is_configuration_string({"en 12": "What is your name?"}), "Invalid language code") self.assertFalse( helper.is_configuration_string({ "en": "What is your name?", "fr": "" }), "Missing question") self.assertFalse( helper.is_configuration_string({"en": "What is your name?"}, ["fr"]), "Missing a required language") self.assertFalse( helper.is_configuration_string({ "en": "???", "fr": "???" }, [1, 2, 3]), "Illegal required language codes") self.assertFalse(helper.is_configuration_string(""), "Empty string.") self.assertFalse(helper.is_configuration_string(" "), "Empty string (whitespace only).") self.assertFalse(helper.is_configuration_string("\r\n\t"), "Empty string (escape sequences).")
def test_valid_configuration_strings(self): self.assertTrue(helper.is_configuration_string("Hello, World"), "Non-empty string.") self.assertTrue(helper.is_configuration_string(" *"), "String with leading whitespace and asterisk.") self.assertTrue(helper.is_configuration_string("trailblazer "), "String with trailing whitespace.") self.assertTrue(helper.is_configuration_string(" Hello, World "), "String with leading and trailing whitespace.") self.assertTrue(helper.is_configuration_string("\r\n\t\\"), "Escape sequences with backslash character.") self.assertTrue( helper.is_configuration_string( {"en": "What is the answer to life?"}), "Normalized string") self.assertTrue(helper.is_configuration_string({"en": "???"}), "Normalized string (syntactically)") self.assertTrue( helper.is_configuration_string( {"fr-CH": "Mais où est donc Ornicar?"}), "Normalized swiss-french string") self.assertTrue( helper.is_configuration_string({ "en": "What is the answer to life?", "fr": "Mais où est donc Ornicar?" }), "Normalized string with multiple languages") self.assertTrue( helper.is_configuration_string({ "en": "???", "fr": "???" }, []), "Normalized string with an empty list of required languages") self.assertTrue( helper.is_configuration_string({ "en": "???", "fr": "???" }, ["en"]), "Normalized string with required language") self.assertTrue( helper.is_configuration_string({ "en": "???", "fr": "???" }, ["en", "fr"]), "Normalized string with multiple required languages")
def test_illegal_configuration_strings(self): self.assertRaises(TypeError, helper.is_configuration_string, None) self.assertRaises(TypeError, helper.is_configuration_string, 42) self.assertRaises(TypeError, helper.is_configuration_string, []) self.assertRaises(TypeError, helper.is_configuration_string, {}, 42) self.assertRaises(TypeError, helper.is_configuration_string, {}, ("en", "fr")) self.assertRaises(TypeError, helper.is_configuration_string, {}, "") self.assertFalse(helper.is_configuration_string({}), "Empty dictionary") self.assertFalse(helper.is_configuration_string({"en":""}), "Empty string with a valid language code") self.assertFalse(helper.is_configuration_string({"en":None}), "Valid language code with non-string (None) value") self.assertFalse(helper.is_configuration_string({"en":32}), "Valid language code with non-string (int) value") self.assertFalse(helper.is_configuration_string({"en":{}}), "Valid language code with non-string (dict) value") self.assertFalse(helper.is_configuration_string({"en 12":"What is your name?"}), "Invalid language code") self.assertFalse(helper.is_configuration_string({"en":"What is your name?", "fr":""}), "Missing question") self.assertFalse(helper.is_configuration_string({"en":"What is your name?"}, ["fr"]), "Missing a required language") self.assertFalse(helper.is_configuration_string({"en":"???", "fr":"???"}, [1, 2, 3]), "Illegal required language codes") self.assertFalse(helper.is_configuration_string(""), "Empty string.") self.assertFalse(helper.is_configuration_string(" "), "Empty string (whitespace only).") self.assertFalse(helper.is_configuration_string("\r\n\t"), "Empty string (escape sequences).")
def test_valid_configuration_strings(self): self.assertTrue(helper.is_configuration_string("Hello, World"), "Non-empty string.") self.assertTrue(helper.is_configuration_string(" *"), "String with leading whitespace and asterisk.") self.assertTrue(helper.is_configuration_string("trailblazer "), "String with trailing whitespace.") self.assertTrue(helper.is_configuration_string(" Hello, World "), "String with leading and trailing whitespace.") self.assertTrue(helper.is_configuration_string("\r\n\t\\"), "Escape sequences with backslash character.") self.assertTrue(helper.is_configuration_string({"en":"What is the answer to life?"}), "Normalized string") self.assertTrue(helper.is_configuration_string({"en":"???"}), "Normalized string (syntactically)") self.assertTrue(helper.is_configuration_string({"fr-CH":"Mais où est donc Ornicar?"}), "Normalized swiss-french string") self.assertTrue(helper.is_configuration_string({"en":"What is the answer to life?", "fr":"Mais où est donc Ornicar?"}), "Normalized string with multiple languages") self.assertTrue(helper.is_configuration_string({"en":"???", "fr":"???"}, []), "Normalized string with an empty list of required languages") self.assertTrue(helper.is_configuration_string({"en":"???", "fr":"???"}, ["en"]), "Normalized string with required language") self.assertTrue(helper.is_configuration_string({"en":"???", "fr":"???"}, ["en", "fr"]), "Normalized string with multiple required languages")