Example #1
0
class TestInputy(unittest.TestCase):
    """
    Test case for inputy functionality

    Here, it is not necessary to test whether the prompted message has the
    correct format because it uses the methods already tested in the Printy
    test cases
    """
    def setUp(self):
        self.inputy = Printy()

    str_valid_test = "Valid String"
    int_valid_test = 23
    float_valid_test = 45.6
    bool_valid_test = False

    def test_normalize_options_not_enough_options_raises_value_error(self):
        """
        Tests that passing a list with less than 2 items as 'options' raises
        a Value Error when input_type is different than 'bool'
        """
        with self.assertRaises(ValueError):
            self.inputy._normalize_options([], self.inputy.STR)

    def test_normalize_options_bool_more_than_two_items_get_the_first_two(
            self):
        """
        Tests that passing more than 2 items as options for input_type 'bool'
        returns only the first two
        """
        options = ['yes', 'no', 'Yep', 'Nope']
        normalized_options = self.inputy._normalize_options(
            options, self.inputy.BOOL)
        expected_options = {'1': 'yes', '2': 'no'}

        self.assertEqual(normalized_options, expected_options)

    def test_normalize_options_bool_less_than_two_items_returns_tru_false(
            self):
        """
        Tests that passing more than 2 items as options for input_type 'bool'
        returns only the first two
        """
        options = ['yes']
        normalized_options = self.inputy._normalize_options(
            options, self.inputy.BOOL)
        expected_options = {'1': 'True', '2': 'False'}

        self.assertEqual(normalized_options, expected_options)

    def test_check_boolean_case_insensitive(self):
        """
        Test that passing a different case for one of the options still
        returns the value
        """
        options = {'1': 'y', '2': 'n'}
        value = 'Y'
        result, valid = self.inputy.check_boolean(value, options, 'i')

        self.assertEqual(result, True)
        self.assertEqual(valid, True)

    def test_check_boolean_case_sensitive(self):
        """
        Test that passing a different case for one of the options returns
        an invalid value
        """
        options = {'1': 'y', '2': 'n'}
        value = 'Y'
        result, valid = self.inputy.check_boolean(value, options, '')

        self.assertEqual(result, False)
        self.assertEqual(valid, False)

    def test_check_integer_no_condition(self):
        """
        Tests that passing no condition to check an integer returns the value
        """
        positive_value = 5
        negative_value = -5
        condition = ''
        result_positive, valid_positive = self.inputy.check_integer(
            str(positive_value), condition)
        result_negative, valid_negative = self.inputy.check_integer(
            str(negative_value), condition)

        self.assertTrue(valid_positive)
        self.assertTrue(valid_negative)
        self.assertEqual(result_positive, 5)
        self.assertEqual(result_negative, -5)

    def test_check_integer_condition_only_positive(self):
        """
        Test that passing a condition '-' to the check_integer function will
        return a valid value only when the value is negative
        """
        positive_value = 5
        negative_value = -5
        condition = '-'
        result_positive, valid_positive = self.inputy.check_integer(
            str(positive_value), condition)
        result_negative, valid_negative = self.inputy.check_integer(
            str(negative_value), condition)

        self.assertFalse(valid_positive)
        self.assertTrue(valid_negative)

        self.assertEqual(result_positive, 5)
        self.assertEqual(result_negative, -5)

    def test_check_integer_condition_only_negative(self):
        """
        Test that passing a condition '-' to the check_integer function will
        return a valid value only when the value is negative
        """
        positive_value = 5
        negative_value = -5
        condition = '+'
        result_positive, valid_positive = self.inputy.check_integer(
            str(positive_value), condition)
        result_negative, valid_negative = self.inputy.check_integer(
            str(negative_value), condition)

        self.assertTrue(valid_positive)
        self.assertFalse(valid_negative)

        self.assertEqual(result_positive, 5)
        self.assertEqual(result_negative, -5)

    def test_check_float_no_condition(self):
        """
        Tests that passing no condition to check a float returns the value
        """
        positive_value = 5.0
        negative_value = -5.0
        condition = ''
        result_positive, valid_positive = self.inputy.check_float(
            str(positive_value), condition)
        result_negative, valid_negative = self.inputy.check_float(
            str(negative_value), condition)

        self.assertTrue(valid_positive)
        self.assertTrue(valid_negative)
        self.assertEqual(result_positive, 5.0)
        self.assertEqual(result_negative, -5.0)

    def test_check_float_condition_only_positive(self):
        """
        Test that passing a condition '-' to the check_float function will
        return a valid value only when the value is negative
        """
        positive_value = 5.0
        negative_value = -5.0
        condition = '-'
        result_positive, valid_positive = self.inputy.check_float(
            str(positive_value), condition)
        result_negative, valid_negative = self.inputy.check_float(
            str(negative_value), condition)

        self.assertFalse(valid_positive)
        self.assertTrue(valid_negative)

        self.assertEqual(result_positive, 5.0)
        self.assertEqual(result_negative, -5.0)

    def test_check_float_condition_only_negative(self):
        """
        Test that passing a condition '-' to the check_float function will
        return a valid value only when the value is negative
        """
        positive_value = 5.0
        negative_value = -5.0
        condition = '+'
        result_positive, valid_positive = self.inputy.check_float(
            str(positive_value), condition)
        result_negative, valid_negative = self.inputy.check_float(
            str(negative_value), condition)

        self.assertTrue(valid_positive)
        self.assertFalse(valid_negative)

        self.assertEqual(result_positive, 5.0)
        self.assertEqual(result_negative, -5.0)

    def test_check_string_options_by_number_case_sensitive(self):
        """
        Tests that, passing a set of options, the correct value is returned if
        user enters the number of the item in the list (case sensitive scenario)
        """
        options = {'1': 'Oranges', '2': 'Apples', '3': 'Pineapples'}
        selected = 3
        expected_returned_value = options[str(selected)]

        result, valid = self.inputy.check_string(str(selected), options, '')

        self.assertTrue(valid)
        self.assertEqual(result, expected_returned_value)

    def test_check_string_options_by_number_case_insensitive(self):
        """
        Tests that, passing a set of options, the correct value is returned if
        user enters the number of the item in the list (case insensitive scenario)
        """
        options = {'1': 'Oranges', '2': 'Apples', '3': 'Pineapples'}
        selected = 3
        expected_returned_value = options[str(selected)]

        result, valid = self.inputy.check_string(str(selected), options, 'i')

        self.assertTrue(valid)
        self.assertEqual(result, expected_returned_value)

    def test_check_string_options_invalid_by_number_case_insensitive(self):
        """
        Tests that, passing a set of options, the correct value is returned if
        user enters the number of the item in the list (case insensitive scenario)
        """
        options = {'1': 'Oranges', '2': 'Apples', '3': 'Pineapples'}
        selected = 6  # invalid
        expected_returned_value = str(selected)

        result, valid = self.inputy.check_string(str(selected), options, 'i')

        self.assertFalse(valid)
        self.assertEqual(result, expected_returned_value)

    def test_check_string_options_case_insensitive(self):
        """
        Test that passing a different case for one of the options still
        returns the value
        """
        options = {'1': 'Oranges', '2': 'Apples', '3': 'Pineapples'}
        selected_capital_case = 'ORANGES'
        selected_lower_case = 'oranges'
        expected_returned_value = options['1']

        result_capital, valid_capital = self.inputy.check_string(
            selected_capital_case, options, 'i')
        result_lower, valid_lower = self.inputy.check_string(
            selected_lower_case, options, 'i')

        self.assertTrue(valid_capital)
        self.assertTrue(valid_lower)

        self.assertEqual(result_capital, expected_returned_value)
        self.assertEqual(result_lower, expected_returned_value)

    def test_check_string_case_sensitive(self):
        """
        Test that passing a different case for one of the options returns
        an invalid value
        """
        options = {'1': 'Oranges', '2': 'Apples', '3': 'Pineapples'}
        selected_capital_case = 'ORANGES'
        selected_matched_case = 'Oranges'
        expected_returned_value = options['1']

        result_capital, valid_capital = self.inputy.check_string(
            selected_capital_case, options, '')
        result_matched, valid_matched = self.inputy.check_string(
            selected_matched_case, options, '')

        self.assertFalse(valid_capital)
        self.assertTrue(valid_matched)

        self.assertEqual(result_matched, expected_returned_value)

    @mock.patch('builtins.input', return_value=str_valid_test)
    def test_passing_no_parameters_returns_a_value_str(self, mock_input):
        """ Testing 'inputy' as a normal 'input()' function """
        result_str = self.inputy.format_input()
        self.assertEqual(result_str, self.str_valid_test)

    @mock.patch('builtins.input', return_value=int_valid_test)
    def test_passing_no_parameters_returns_a_value_str_from_int(
            self, mock_input):
        """ Testing 'inputy' as a normal 'input()' function """
        result_str_from_int = self.inputy.format_input()
        self.assertEqual(result_str_from_int, str(self.int_valid_test))

    @mock.patch('builtins.input',
                side_effect=[
                    str_valid_test, bool_valid_test, float_valid_test, None,
                    int_valid_test
                ])
    def test_passed_invalid_when_requested_int(self, mock_input):
        """
        Test that, when specifying the users has to enter an integer,
        the message is prompted until a valid number is passed
        """
        result_valid_int = self.inputy.format_input(type='int')

        self.assertEqual(result_valid_int, self.int_valid_test)

    @mock.patch(
        'builtins.input',
        side_effect=[None, str_valid_test, bool_valid_test, float_valid_test])
    def test_passed_invalid_when_requested_float(self, mock_input):
        """
        Test that, when specifying the users has to enter a number,
        the message is prompted until a valid number is passed
        """
        result_valid_int = self.inputy.format_input(type='float')

        self.assertEqual(result_valid_int, self.float_valid_test)

    @mock.patch(
        'builtins.input',
        side_effect=[str_valid_test, None, int_valid_test, bool_valid_test])
    def test_passed_invalid_when_requested_boolean(self, mock_input):
        """
        Test that, when specifying the user has to enter a boolean
        the message is prompted until a boolean is passed
        """
        result_valid_boolean = self.inputy.format_input(type='bool')

        self.assertEqual(result_valid_boolean, self.bool_valid_test)

    @mock.patch('builtins.input',
                side_effect=[str_valid_test, None, int_valid_test, 'True'])
    def test_passed_invalid_when_requested_boolean_str(self, mock_input):
        """
        Test that, when specifying the user has to enter a boolean
        the message is prompted until a test case insensitive with the name of
        one of the boolean values is passed
        """
        result_valid_boolean = self.inputy.format_input(type='bool')

        self.assertEqual(result_valid_boolean, True)

    @mock.patch('builtins.input', return_value=str_valid_test)
    def test_passing_and_invalid_input_type(self, mock_input):
        """
        Tests that passing and invalid input type raises an InvalidInputType
        exception. We mock the input() just in case the tests reaches that section
        """
        invalid_input_type = 'not_int_nor_float'
        with self.assertRaises(InvalidInputType) as e:
            self.inputy.format_input(type=invalid_input_type)
        self.assertEqual(e.exception.input_type, invalid_input_type)

    def test_converting_value_to_integer(self):
        number_as_string_value = '2'
        invalid_string = 'Not a number as a string'
        none_value = None

        self.assertEqual(Printy._to_int(number_as_string_value), 2)
        self.assertEqual(Printy._to_int(none_value), None)
        with self.assertRaises(ValueError):
            Printy._to_int(invalid_string)

    def test_max_digits(self):
        """ Tests restriction when passing a max_digits parameter """

        max_digits = 3
        invalid_number = '1234'
        valid_number = '123'

        invalid_number_value, invalid_number_valid_value = self.inputy._check_number(
            int, value=invalid_number, max_digits=max_digits)
        valid_number_value, valid_number_valid_value = self.inputy._check_number(
            int, valid_number, max_digits=max_digits)

        self.assertTrue(valid_number_valid_value)
        self.assertFalse(invalid_number_valid_value)

    def test_max_decimals(self):
        """ Tests restriction when passing a max_decimals parameter """

        max_decimals = 3
        invalid_number = '1234.1234'
        valid_number = '1234.123'

        invalid_number_value, invalid_number_valid_value = self.inputy._check_number(
            float, value=invalid_number, max_decimals=max_decimals)
        valid_number_value, valid_number_valid_value = self.inputy._check_number(
            float, valid_number, max_decimals=max_decimals)

        self.assertTrue(valid_number_valid_value)
        self.assertFalse(invalid_number_valid_value)
Example #2
0
class TestInputy(unittest.TestCase):
    """
    Test case for inputy functionality

    Here, it is not necessary to test whether the prompted message has the
    correct format because it uses the methods already tested in the Printy
    test cases
    """
    def setUp(self):
        self.inputy = Printy()

    str_valid_test = "Valid String"
    int_valid_test = 23
    float_valid_test = 45.6
    bool_valid_test = False

    def test_get_bool_options_case_insensitive(self):
        """
        Tests returning True for the insensitive value if 'i' is passed as
        the first character of the 'options' parameter
        """
        options = 'i{y/n}'
        insensitive, true_option, false_option = self.inputy.get_bool_options(
            options)

        self.assertTrue(insensitive)
        self.assertEqual(true_option, 'y')
        self.assertEqual(false_option, 'n')

    def test_get_bool_options_case_sensitive(self):
        """
        Tests returning True for the insensitive value if no 'i' is passed as
        the first character of the 'options' parameter
        """
        options = 'y/n'
        insensitive, true_option, false_option = self.inputy.get_bool_options(
            options)

        self.assertFalse(insensitive)
        self.assertEqual(true_option, 'y')
        self.assertEqual(false_option, 'n')

    def test_default_value_options(self):
        """
        Tests return the default 'True' and 'False' and case insensitive if no
        options are passed
        """
        options = ''
        insensitive, true_option, false_option = self.inputy.get_bool_options(
            options)

        self.assertTrue(insensitive)
        self.assertTrue(true_option)
        self.assertFalse(false_option)

    def test_passing_wrong_flag_for_case_insensitive(self):
        """
        Tests that passing a value different than 'i' for the insensitive
        flag in in 'options' parameter when the type is bool, raises an exception
        """
        options = 'f{y/n}'
        with self.assertRaises(BoolOptionsNotValid) as e:
            self.inputy.get_bool_options(options)
        self.assertEqual(e.exception.options, options)

    def test_passing_invalid_options_to_bool_type(self):
        """
        Tests that passing an invalid option value to the parameter 'options'
        raises an BoolOptionsNotValid
        """
        invalid_options = "jgnlf"
        with self.assertRaises(BoolOptionsNotValid) as e:
            self.inputy.get_bool_options(invalid_options)
        self.assertEqual(e.exception.options, invalid_options)

    def test_get_int_options(self):
        """ Test returning valid options"""
        positive = '+'
        negative = '-'
        int_options_positive = self.inputy.get_int_options(positive)
        int_options_negative = self.inputy.get_int_options(negative)

        self.assertEqual(positive, int_options_positive)
        self.assertEqual(negative, int_options_negative)

    def test_passing_long_character_as_int_options(self):
        """
        Tests that passing more than one character (only + or - are allowed)
        raises an exception
        """
        long_int_options_one = '+-'
        long_int_options_two = 'plus'

        with self.assertRaises(IntOptionsNotValid) as e_one:
            self.inputy.get_int_options(long_int_options_one)
        with self.assertRaises(IntOptionsNotValid) as e_two:
            self.inputy.get_int_options(long_int_options_two)
        self.assertEqual(e_one.exception.options, long_int_options_one)
        self.assertEqual(e_two.exception.options, long_int_options_two)

    def test_check_boolean_case_sensitive_returns_value_converted(self):
        """
        tests that passing a value (according to the options) to a type='bool'
        returns a converted value (True or False)
        """
        options = 'y/n'
        value_true = 'y'
        value_false = 'n'
        returned_value_true, valid_value_true = self.inputy.check_boolean(
            value_true, options)
        returned_value_false, valid_value_false = self.inputy.check_boolean(
            value_false, options)

        self.assertEqual(returned_value_true, True)
        self.assertEqual(returned_value_false, False)
        self.assertTrue(valid_value_true)
        self.assertTrue(valid_value_false)

    def test_check_boolean_case_insensitive_returns_value_converted(self):
        """
        tests that passing a value with different case (according to the options
        as case insensitive) to a type='bool' returns a converted value (True or False)
        """
        options = 'i{y/n}'
        value_true = 'Y'
        value_false = 'N'
        returned_value_true, valid_value_true = self.inputy.check_boolean(
            value_true, options)
        returned_value_false, valid_value_false = self.inputy.check_boolean(
            value_false, options)

        self.assertEqual(returned_value_true, True)
        self.assertEqual(returned_value_false, False)
        self.assertTrue(valid_value_true)
        self.assertTrue(valid_value_false)

    def test_check_boolean_invalid_value(self):
        """
        tests passing an invalid value to check_bool returns False as the value
        and also False as 'valid_value'
        """
        options = 'i{y/n}'
        value_true = 'Yes'
        value_false = 'No'
        returned_value_true, valid_value_true = self.inputy.check_boolean(
            value_true, options)
        returned_value_false, valid_value_false = self.inputy.check_boolean(
            value_false, options)

        self.assertEqual(returned_value_true, False)
        self.assertEqual(returned_value_false, False)
        self.assertFalse(valid_value_true)
        self.assertFalse(valid_value_false)

    def test_check_integer_returns_converted_value(self):
        """ tests that check_integer returns the value converted as integer"""
        value = 34
        returned_value, valid_value = self.inputy.check_integer(value)

        self.assertTrue(isinstance(returned_value, int))
        self.assertEqual(returned_value, value)
        self.assertTrue(valid_value)

    def test_check_integer_with_positive_option(self):
        """
        Tests that passing '+' as options for type='int' returns the converted
        value and valid_value as False if it is not a positive number
        """
        opts_positive = '+'
        valid_int = 34
        invalid_int = -34
        return_valid_int, valid_value_valid_int = self.inputy.check_integer(
            valid_int, opts_positive)
        return_invalid_int, valid_value_invalid_int = self.inputy.check_integer(
            invalid_int, opts_positive)

        self.assertTrue(isinstance(return_valid_int, int))
        self.assertEqual(return_valid_int, valid_int)
        self.assertTrue(valid_value_valid_int)

        self.assertTrue(isinstance(return_invalid_int, int))
        self.assertEqual(return_invalid_int, invalid_int)
        self.assertFalse(valid_value_invalid_int)

    def test_check_integer_with_negative_option(self):
        """
        Tests that passing '-' as options for type='int' returns the converted
        value and valid_value as False if it is not a negative number
        """
        opts_positive = '-'
        valid_int = -34
        invalid_int = 34
        return_valid_int, valid_value_valid_int = self.inputy.check_integer(
            valid_int, opts_positive)
        return_invalid_int, valid_value_invalid_int = self.inputy.check_integer(
            invalid_int, opts_positive)

        self.assertTrue(isinstance(return_valid_int, int))
        self.assertEqual(return_valid_int, valid_int)
        self.assertTrue(valid_value_valid_int)

        self.assertTrue(isinstance(return_invalid_int, int))
        self.assertEqual(return_invalid_int, invalid_int)
        self.assertFalse(valid_value_invalid_int)

    def test_check_float_returns_converted_value(self):
        """ tests that check_float returns the value converted as float"""
        value = 34.5
        returned_value, valid_value = self.inputy.check_float(value)

        self.assertTrue(isinstance(returned_value, float))
        self.assertEqual(returned_value, value)
        self.assertTrue(valid_value)

    def test_check_float_with_positive_option(self):
        """
        Tests that passing '+' as options for type='float' returns the converted
        value and valid_value as False if it is not a positive number
        """
        opts_positive = '+'
        valid_int = 34.5
        invalid_int = -34.5
        return_valid_int, valid_value_valid_int = self.inputy.check_float(
            valid_int, opts_positive)
        return_invalid_int, valid_value_invalid_int = self.inputy.check_float(
            invalid_int, opts_positive)

        self.assertTrue(isinstance(return_valid_int, float))
        self.assertEqual(return_valid_int, valid_int)
        self.assertTrue(valid_value_valid_int)

        self.assertTrue(isinstance(return_invalid_int, float))
        self.assertEqual(return_invalid_int, invalid_int)
        self.assertFalse(valid_value_invalid_int)

    def test_check_float_with_negative_option(self):
        """
        Tests that passing '-' as options for type='float' returns the converted
        value and valid_value as False if it is not a negative number
        """
        opts_positive = '-'
        valid_int = -34.0
        invalid_int = 34.0
        return_valid_int, valid_value_valid_int = self.inputy.check_float(
            valid_int, opts_positive)
        return_invalid_int, valid_value_invalid_int = self.inputy.check_float(
            invalid_int, opts_positive)

        self.assertTrue(isinstance(return_valid_int, float))
        self.assertEqual(return_valid_int, valid_int)
        self.assertTrue(valid_value_valid_int)

        self.assertTrue(isinstance(return_invalid_int, float))
        self.assertEqual(return_invalid_int, invalid_int)
        self.assertFalse(valid_value_invalid_int)

    @mock.patch('builtins.input', return_value=str_valid_test)
    def test_passing_no_parameters_returns_a_value_str(self, mock_input):
        """ Testing 'inputy' as a normal 'input()' function """
        result_str = self.inputy.format_input()
        self.assertEqual(result_str, self.str_valid_test)

    @mock.patch('builtins.input', return_value=int_valid_test)
    def test_passing_no_parameters_returns_a_value_str_from_int(
            self, mock_input):
        """ Testing 'inputy' as a normal 'input()' function """
        result_str_from_int = self.inputy.format_input()
        self.assertEqual(result_str_from_int, str(self.int_valid_test))

    @mock.patch('builtins.input',
                side_effect=[
                    str_valid_test, bool_valid_test, float_valid_test, None,
                    int_valid_test
                ])
    def test_passed_invalid_when_requested_int(self, mock_input):
        """
        Test that, when specifying the users has to enter an integer,
        the message is prompted until a valid number is passed
        """
        result_valid_int = self.inputy.format_input(type='int')

        self.assertEqual(result_valid_int, self.int_valid_test)

    @mock.patch(
        'builtins.input',
        side_effect=[None, str_valid_test, bool_valid_test, float_valid_test])
    def test_passed_invalid_when_requested_float(self, mock_input):
        """
        Test that, when specifying the users has to enter a number,
        the message is prompted until a valid number is passed
        """
        result_valid_int = self.inputy.format_input(type='float')

        self.assertEqual(result_valid_int, self.float_valid_test)

    @mock.patch(
        'builtins.input',
        side_effect=[str_valid_test, None, int_valid_test, bool_valid_test])
    def test_passed_invalid_when_requested_boolean(self, mock_input):
        """
        Test that, when specifying the user has to enter a boolean
        the message is prompted until a boolean is passed
        """
        result_valid_boolean = self.inputy.format_input(type='bool')

        self.assertEqual(result_valid_boolean, self.bool_valid_test)

    @mock.patch('builtins.input',
                side_effect=[str_valid_test, None, int_valid_test, 'true'])
    def test_passed_invalid_when_requested_boolean_str(self, mock_input):
        """
        Test that, when specifying the user has to enter a boolean
        the message is prompted until a test case insensitive with the name of
        one of the boolean values is passed
        """
        result_valid_boolean = self.inputy.format_input(type='bool')

        self.assertEqual(result_valid_boolean, True)

    @mock.patch('builtins.input', return_value=str_valid_test)
    def test_passing_and_invalid_input_type(self, mock_input):
        """
        Tests that passing and invalid input type raises an InvalidInputType
        exception. We mock the input() just in case the tests reaches that section
        """
        invalid_input_type = 'not_int_nor_float'
        with self.assertRaises(InvalidInputType) as e:
            self.inputy.format_input(type=invalid_input_type)
        self.assertEqual(e.exception.input_type, invalid_input_type)