def _test_non_strict_matching(self, padding_char):
        """
        Allows to test strict matching with a specific padding character.

        :param padding_char: Character to test padding with. Should be space or 0.
        """
        key = IntegerKey("version_number", format_spec="%s3" % padding_char, strict_matching=False)

        # The padding char is missing in the format specifier, but we still need when validating
        # results.
        if padding_char == '':
            padding_char = ' '

        # It should match because they are valid numbers.

        self.assertEqual(key.value_from_str("000"), 0)
        self.assertEqual(key.value_from_str("0"), 0)
        self.assertEqual(key.value_from_str("0"), 0)

        # While the number doesn't make any sense as far as formatting is concerned, this used
        # to work in old versions of Toolkit and needs to keep working in non strict mode.
        self.assertEqual(key.value_from_str("%s000" % padding_char), 0)

        # It should match a template with too many digits...
        self.assertEqual(key.value_from_str("20000"), 20000)

        # ... even if they are all zeros because lossy matching.
        self.assertEqual(key.value_from_str("00000"), 0)

        # From path to tokens back to path should be lossy.
        value = key.value_from_str("1")
        self.assertEqual("%s%s1" % (padding_char, padding_char), key.str_from_value(value))

        self._test_nan(key, "expected an Integer")
Beispiel #2
0
    def _test_non_strict_matching(self, padding_char):
        """
        Allows to test strict matching with a specific padding character.

        :param padding_char: Character to test padding with. Should be space or 0.
        """
        key = IntegerKey("version_number", format_spec="%s3" % padding_char, strict_matching=False)

        # The padding char is missing in the format specifier, but we still need when validating
        # results.
        if padding_char == '':
            padding_char = ' '

        # It should match because they are valid numbers.

        self.assertEqual(key.value_from_str("000"), 0)
        self.assertEqual(key.value_from_str("0"), 0)
        self.assertEqual(key.value_from_str("0"), 0)

        # While the number doesn't make any sense as far as formatting is concerned, this used
        # to work in old versions of Toolkit and needs to keep working in non strict mode.
        self.assertEqual(key.value_from_str("%s000" % padding_char), 0)

        # It should match a template with too many digits...
        self.assertEqual(key.value_from_str("20000"), 20000)

        # ... even if they are all zeros because lossy matching.
        self.assertEqual(key.value_from_str("00000"), 0)

        # From path to tokens back to path should be lossy.
        value = key.value_from_str("1")
        self.assertEqual("%s%s1" % (padding_char, padding_char), key.str_from_value(value))

        self._test_nan(key, "expected an Integer")
Beispiel #3
0
class TestIntegerKey(TankTestBase):
    def setUp(self):
        super(TestIntegerKey, self).setUp()
        self.int_field = IntegerKey("field_name")

    def test_bad_default(self):
        """Case that specified default does not match type."""
        default_value = "default_value"
        self.assertRaises(TankError,
                          IntegerKey,
                          "field_name",
                          default=default_value)

    def test_illegal_choice(self):
        """Choice conflict with type."""
        choices_value = ["a", "b"]
        self.assertRaises(TankError,
                          IntegerKey,
                          "field_name",
                          choices=choices_value)

    def test_format_set(self):
        format_spec = "03"
        template_field = IntegerKey("field_name", format_spec=format_spec)
        self.assertEquals(format_spec, template_field.format_spec)

    def test_validate_string_good(self):
        value = "23"
        self.assertTrue(self.int_field.validate(value))

    def test_validate_int_good(self):
        value = 23
        self.assertTrue(self.int_field.validate(value))

    def test_validate_bad(self):
        value = "a"
        self.assertFalse(self.int_field.validate(value))

    def test_str_from_value_good(self):
        value = 3
        expected = "%s" % value
        result = self.int_field.str_from_value(value)
        self.assertEquals(expected, result)

    def test_str_from_value_zero(self):
        value = 0
        expected = "%d" % value
        result = self.int_field.str_from_value(value)
        self.assertEquals(expected, result)

    def test_str_from_value_bad(self):
        value = "a"
        expected = "%s Illegal value %s, expected an Integer" % (str(
            self.int_field), value)
        self.check_error_message(TankError, expected,
                                 self.int_field.str_from_value, value)

    def test_str_from_value_formatted(self):
        formatted_field = IntegerKey("field_name", format_spec="03")
        value = 3
        expected = "%03d" % value
        result = formatted_field.str_from_value(value)
        self.assertEquals(expected, result)

    def test_str_from_value_ignore_type(self):
        value = "a"
        expected = value
        result = self.int_field.str_from_value(value, ignore_type=True)
        self.assertEquals(expected, result)

    def test_value_from_str(self):
        str_value = "32"
        self.assertEquals(32, self.int_field.value_from_str(str_value))

    def test_repr(self):
        expected = "<Sgtk IntegerKey field_name>"
        self.assertEquals(expected, str(self.int_field))
Beispiel #4
0
    def _test_strict_matching(self, padding_char):
        """
        Allows to test strict matching with any padding type.
        """
        # have a template that formats with two digits of padding.
        key = IntegerKey("version_number",
                         format_spec="%s3" % padding_char,
                         strict_matching=True)
        self.assertTrue(key.strict_matching)

        # The padding char is missing in the format specifier, but we still need when validating
        # results.
        if padding_char == "":
            padding_char = " "

        # From path to tokens back to path should get back the same string when the expected number of
        # digits are found.
        value = key.value_from_str("%s%s1" % (padding_char, padding_char))
        self.assertEqual("%s%s1" % (padding_char, padding_char),
                         key.str_from_value(value))

        # It should match a template with more digits.
        value = key.value_from_str("20000")
        self.assertEqual("20000", key.str_from_value(value))

        key.value_from_str("123")

        error_msg = "does not match format spec"

        # It should not match a string with too few digits
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("1")

        # It should not match a template with too many digits that are all zero because that would
        # lossy. (there are more zeros than the format spec can rebuild)
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("0000")

        # It should not match negative numbers either
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("-1000")

        # It should not match baddly padded numbers
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("0100")

        # It should not match negative values
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("-01")

        self._test_nan(key, error_msg)
Beispiel #5
0
class TestIntegerKey(ShotgunTestBase):
    def setUp(self):
        super(TestIntegerKey, self).setUp()
        self.int_field = IntegerKey("field_name")

    def test_bad_default(self):
        """Case that specified default does not match type."""
        default_value = "default_value"
        self.assertRaises(TankError,
                          IntegerKey,
                          "field_name",
                          default=default_value)

    def test_illegal_choice(self):
        """Choice conflict with type."""
        choices_value = ["a", "b"]
        self.assertRaises(TankError,
                          IntegerKey,
                          "field_name",
                          choices=choices_value)

    def test_format_set(self):
        format_spec = "03"
        template_field = IntegerKey("field_name", format_spec=format_spec)
        self.assertEqual(format_spec, template_field.format_spec)

    def test_validate_string_good(self):
        value = "23"
        self.assertTrue(self.int_field.validate(value))

    def test_validate_int_good(self):
        value = 23
        self.assertTrue(self.int_field.validate(value))

    def test_validate_bad(self):
        value = "a"
        self.assertFalse(self.int_field.validate(value))

    def test_str_from_value_good(self):
        value = 3
        expected = "%s" % value
        result = self.int_field.str_from_value(value)
        self.assertEqual(expected, result)

    def test_str_from_value_zero(self):
        value = 0
        expected = "%d" % value
        result = self.int_field.str_from_value(value)
        self.assertEqual(expected, result)

    def test_str_from_value_bad(self):
        value = "a"
        expected = "%s Illegal value '%s', expected an Integer" % (
            str(self.int_field),
            value,
        )
        self.check_error_message(TankError, expected,
                                 self.int_field.str_from_value, value)

    def test_str_from_value_formatted(self):
        formatted_field = IntegerKey("field_name", format_spec="03")
        value = 3
        expected = "%03d" % value
        result = formatted_field.str_from_value(value)
        self.assertEqual(expected, result)

    def test_str_from_value_ignore_type(self):
        value = "a"
        expected = value
        result = self.int_field.str_from_value(value, ignore_type=True)
        self.assertEqual(expected, result)

    def test_value_from_str(self):
        str_value = "32"
        self.assertEqual(32, self.int_field.value_from_str(str_value))

    def test_repr(self):
        expected = "<Sgtk IntegerKey field_name>"
        self.assertEqual(expected, str(self.int_field))

    def test_init_validation(self):
        """
        Makes sure that parameter validation is correct in the constructor.
        """
        # This should obviously work
        self._validate_key(IntegerKey("version_number"),
                           strict_matching=None,
                           format_spec=None)
        # When specifying parameters, they should be set accordingly.
        self._validate_key(
            IntegerKey("version_number",
                       format_spec="03",
                       strict_matching=True),
            strict_matching=True,
            format_spec="03",
        )
        self._validate_key(
            IntegerKey("version_number",
                       format_spec="03",
                       strict_matching=False),
            strict_matching=False,
            format_spec="03",
        )
        self._validate_key(
            IntegerKey("version_number",
                       format_spec="3",
                       strict_matching=False),
            strict_matching=False,
            format_spec="3",
        )
        # When specifying a format but not specifying the strict_matching, it should
        # still have strict_matching.
        self._validate_key(
            IntegerKey("version_number", format_spec="03"),
            strict_matching=True,
            format_spec="03",
        )
        # Make sure than an error is raised when wrong types are passed in.
        with self.assertRaisesRegex(TankError, "is not of type boolean"):
            IntegerKey("version_number", strict_matching=1)

        with self.assertRaisesRegex(TankError, "is not of type string"):
            IntegerKey("version_number", format_spec=1)

        # Make sure that if the user specifies strict_matching with no format
        # there is an error
        error_regexp = "strict_matching can't be set"
        with self.assertRaisesRegex(TankError, error_regexp):
            IntegerKey("version_number", strict_matching=False)

        with self.assertRaisesRegex(TankError, error_regexp):
            IntegerKey("version_number", strict_matching=True)

        # We support 4 format_spec values:
        # - None
        # - non zero positive number
        # - zero followed by a non zero positive number
        IntegerKey("version_number", format_spec=None)
        IntegerKey("version_number", format_spec="1")
        IntegerKey("version_number", format_spec="01")

        # Make sure invalid formats are caught
        with self.assertRaisesRegex(TankError, "format_spec can't be empty"):
            IntegerKey("version_number", format_spec="")

        error_regexp = "has to either be"
        # We don't support the sign option.
        with self.assertRaisesRegex(TankError, error_regexp):
            IntegerKey("version_number",
                       format_spec=" 3",
                       strict_matching=False)

        with self.assertRaisesRegex(TankError, error_regexp):
            # Should throw because the padding number is not non zero.
            IntegerKey("version_number", format_spec="00")

        with self.assertRaisesRegex(TankError, error_regexp):
            # Should throw because it is not a non zero positive integer
            IntegerKey("version_number", format_spec="0")

        with self.assertRaisesRegex(TankError, error_regexp):
            # Should throw because the padding caracter is invalid
            IntegerKey("version_number", format_spec="a0")

        with self.assertRaisesRegex(TankError, error_regexp):
            # Should throw because the padding size is not a number.
            IntegerKey("version_number", format_spec="0a")

    def test_no_format_spec(self):
        key = IntegerKey("version_number")
        key.value_from_str

    def _validate_key(self, key, strict_matching, format_spec):
        """
        Makes sure that an integer key's formatting options are correctly set.
        """
        self.assertEqual(key.strict_matching, strict_matching)
        self.assertEqual(key.format_spec, format_spec)

    def test_non_strict_matching(self):
        """
        In non strict mode, tokens can actually have less numbers than the padding requests. Also,
        if there are more, can also match.
        """
        self._test_non_strict_matching("0")
        self._test_non_strict_matching("")

    def _test_non_strict_matching(self, padding_char):
        """
        Allows to test strict matching with a specific padding character.

        :param padding_char: Character to test padding with. Should be space or 0.
        """
        key = IntegerKey("version_number",
                         format_spec="%s3" % padding_char,
                         strict_matching=False)

        # The padding char is missing in the format specifier, but we still need when validating
        # results.
        if padding_char == "":
            padding_char = " "

        # It should match because they are valid numbers.

        self.assertEqual(key.value_from_str("000"), 0)
        self.assertEqual(key.value_from_str("0"), 0)
        self.assertEqual(key.value_from_str("0"), 0)

        # While the number doesn't make any sense as far as formatting is concerned, this used
        # to work in old versions of Toolkit and needs to keep working in non strict mode.
        self.assertEqual(key.value_from_str("%s000" % padding_char), 0)

        # It should match a template with too many digits...
        self.assertEqual(key.value_from_str("20000"), 20000)

        # ... even if they are all zeros because lossy matching.
        self.assertEqual(key.value_from_str("00000"), 0)

        # From path to tokens back to path should be lossy.
        value = key.value_from_str("1")
        self.assertEqual("%s%s1" % (padding_char, padding_char),
                         key.str_from_value(value))

        self._test_nan(key, "expected an Integer")

    def _test_nan(self, key, error_msg):
        """
        Tests a key with against values that are not numbers.

        :param key: Key to test.
        :param error_msg: Text that partially matches the error message.
        """
        # Should fail because not a number
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("aaaa")
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("0a")
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("a0")
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("aa")

    def _test_strict_matching(self, padding_char):
        """
        Allows to test strict matching with any padding type.
        """
        # have a template that formats with two digits of padding.
        key = IntegerKey("version_number",
                         format_spec="%s3" % padding_char,
                         strict_matching=True)
        self.assertTrue(key.strict_matching)

        # The padding char is missing in the format specifier, but we still need when validating
        # results.
        if padding_char == "":
            padding_char = " "

        # From path to tokens back to path should get back the same string when the expected number of
        # digits are found.
        value = key.value_from_str("%s%s1" % (padding_char, padding_char))
        self.assertEqual("%s%s1" % (padding_char, padding_char),
                         key.str_from_value(value))

        # It should match a template with more digits.
        value = key.value_from_str("20000")
        self.assertEqual("20000", key.str_from_value(value))

        key.value_from_str("123")

        error_msg = "does not match format spec"

        # It should not match a string with too few digits
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("1")

        # It should not match a template with too many digits that are all zero because that would
        # lossy. (there are more zeros than the format spec can rebuild)
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("0000")

        # It should not match negative numbers either
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("-1000")

        # It should not match baddly padded numbers
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("0100")

        # It should not match negative values
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("-01")

        self._test_nan(key, error_msg)

    def test_strict_matching(self):
        """
        In strict mode, tokens have to have as much padding as the format specifier suggests. Less will not
        match.
        """
        self._test_strict_matching("")
        self._test_strict_matching("0")
Beispiel #6
0
class TestIntegerKey(TankTestBase):
    def setUp(self):
        super(TestIntegerKey, self).setUp()
        self.int_field = IntegerKey("field_name")

    def test_bad_default(self):
        """Case that specified default does not match type."""
        default_value = "default_value"
        self.assertRaises(TankError, IntegerKey, "field_name", default=default_value)

    def test_illegal_choice(self):
        """Choice conflict with type."""
        choices_value = ["a", "b"]
        self.assertRaises(TankError, IntegerKey, "field_name", choices=choices_value)

    def test_format_set(self):
        format_spec = "03"
        template_field = IntegerKey("field_name", format_spec=format_spec)
        self.assertEquals(format_spec, template_field.format_spec)

    def test_validate_string_good(self):
        value = "23"
        self.assertTrue(self.int_field.validate(value))

    def test_validate_int_good(self):
        value = 23
        self.assertTrue(self.int_field.validate(value))

    def test_validate_bad(self):
        value = "a"
        self.assertFalse(self.int_field.validate(value))

    def test_str_from_value_good(self):
        value = 3
        expected = "%s" % value
        result = self.int_field.str_from_value(value)
        self.assertEquals(expected, result)

    def test_str_from_value_zero(self):
        value = 0
        expected = "%d" % value
        result = self.int_field.str_from_value(value)
        self.assertEquals(expected, result)

    def test_str_from_value_bad(self):
        value = "a"
        expected = "%s Illegal value %s, expected an Integer" % (str(self.int_field), value)
        self.check_error_message(TankError, expected, self.int_field.str_from_value, value)

    def test_str_from_value_formatted(self):
        formatted_field = IntegerKey("field_name", format_spec="03")
        value = 3
        expected = "%03d" % value
        result = formatted_field.str_from_value(value)
        self.assertEquals(expected, result)

    def test_str_from_value_ignore_type(self):
        value = "a"
        expected = value
        result = self.int_field.str_from_value(value, ignore_type=True)
        self.assertEquals(expected, result)

    def test_value_from_str(self):
        str_value = "32"
        self.assertEquals(32, self.int_field.value_from_str(str_value))

    def test_repr(self):
        expected = "<Sgtk IntegerKey field_name>"
        self.assertEquals(expected, str(self.int_field))
    def _test_strict_matching(self, padding_char):
        """
        Allows to test strict matching with any padding type.
        """
        # have a template that formats with two digits of padding.
        key = IntegerKey("version_number", format_spec="%s3" % padding_char, strict_matching=True)
        self.assertTrue(key.strict_matching)

        # The padding char is missing in the format specifier, but we still need when validating
        # results.
        if padding_char == '':
            padding_char = ' '

        # From path to tokens back to path should get back the same string when the expected number of
        # digits are found.
        value = key.value_from_str("%s%s1" % (padding_char, padding_char))
        self.assertEqual("%s%s1" % (padding_char, padding_char), key.str_from_value(value))

        # It should match a template with more digits.
        value = key.value_from_str("20000")
        self.assertEqual("20000", key.str_from_value(value))

        key.value_from_str("123")

        error_msg = "does not match format spec"

        # It should not match a string with too few digits
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("1")

        # It should not match a template with too many digits that are all zero because that would
        # lossy. (there are more zeros than the format spec can rebuild)
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("0000")

        # It should not match negative numbers either
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("-1000")

        # It should not match baddly padded numbers
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("0100")

        # It should not match negative values
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("-01")

        self._test_nan(key, error_msg)
class TestIntegerKey(ShotgunTestBase):
    def setUp(self):
        super(TestIntegerKey, self).setUp()
        self.int_field = IntegerKey("field_name")

    def test_bad_default(self):
        """Case that specified default does not match type."""
        default_value = "default_value"
        self.assertRaises(TankError, IntegerKey, "field_name", default=default_value)

    def test_illegal_choice(self):
        """Choice conflict with type."""
        choices_value = ["a", "b"]
        self.assertRaises(TankError, IntegerKey, "field_name", choices=choices_value)

    def test_format_set(self):
        format_spec = "03"
        template_field = IntegerKey("field_name", format_spec=format_spec)
        self.assertEqual(format_spec, template_field.format_spec)

    def test_validate_string_good(self):
        value = "23"
        self.assertTrue(self.int_field.validate(value))

    def test_validate_int_good(self):
        value = 23
        self.assertTrue(self.int_field.validate(value))

    def test_validate_bad(self):
        value = "a"
        self.assertFalse(self.int_field.validate(value))

    def test_str_from_value_good(self):
        value = 3
        expected = "%s" % value
        result = self.int_field.str_from_value(value)
        self.assertEqual(expected, result)

    def test_str_from_value_zero(self):
        value = 0
        expected = "%d" % value
        result = self.int_field.str_from_value(value)
        self.assertEqual(expected, result)

    def test_str_from_value_bad(self):
        value = "a"
        expected = "%s Illegal value '%s', expected an Integer" % (str(self.int_field), value)
        self.check_error_message(TankError, expected, self.int_field.str_from_value, value)

    def test_str_from_value_formatted(self):
        formatted_field = IntegerKey("field_name", format_spec="03")
        value = 3
        expected = "%03d" % value
        result = formatted_field.str_from_value(value)
        self.assertEqual(expected, result)

    def test_str_from_value_ignore_type(self):
        value = "a"
        expected = value
        result = self.int_field.str_from_value(value, ignore_type=True)
        self.assertEqual(expected, result)

    def test_value_from_str(self):
        str_value = "32"
        self.assertEqual(32, self.int_field.value_from_str(str_value))

    def test_repr(self):
        expected = "<Sgtk IntegerKey field_name>"
        self.assertEqual(expected, str(self.int_field))

    def test_init_validation(self):
        """
        Makes sure that parameter validation is correct in the constructor.
        """
        # This should obviously work
        self._validate_key(
            IntegerKey("version_number"),
            strict_matching=None, format_spec=None
        )
        # When specifying parameters, they should be set accordingly.
        self._validate_key(
            IntegerKey("version_number", format_spec="03", strict_matching=True),
            strict_matching=True, format_spec="03"
        )
        self._validate_key(
            IntegerKey("version_number", format_spec="03", strict_matching=False),
            strict_matching=False, format_spec="03"
        )
        self._validate_key(
            IntegerKey("version_number", format_spec="3", strict_matching=False),
            strict_matching=False, format_spec="3"
        )
        # When specifying a format but not specifying the strict_matching, it should
        # still have strict_matching.
        self._validate_key(
            IntegerKey("version_number", format_spec="03"),
            strict_matching=True, format_spec="03"
        )
        # Make sure than an error is raised when wrong types are passed in.
        with self.assertRaisesRegex(TankError, "is not of type boolean"):
            IntegerKey("version_number", strict_matching=1)

        with self.assertRaisesRegex(TankError, "is not of type string"):
            IntegerKey("version_number", format_spec=1)

        # Make sure that if the user specifies strict_matching with no format
        # there is an error
        error_regexp = "strict_matching can't be set"
        with self.assertRaisesRegex(TankError, error_regexp):
            IntegerKey("version_number", strict_matching=False)

        with self.assertRaisesRegex(TankError, error_regexp):
            IntegerKey("version_number", strict_matching=True)

        # We support 4 format_spec values:
        # - None
        # - non zero positive number
        # - zero followed by a non zero positive number
        IntegerKey("version_number", format_spec=None)
        IntegerKey("version_number", format_spec="1")
        IntegerKey("version_number", format_spec="01")

        # Make sure invalid formats are caught
        with self.assertRaisesRegex(TankError, "format_spec can't be empty"):
            IntegerKey("version_number", format_spec="")

        error_regexp = "has to either be"
        # We don't support the sign option.
        with self.assertRaisesRegex(TankError, error_regexp):
            IntegerKey("version_number", format_spec=" 3", strict_matching=False)

        with self.assertRaisesRegex(TankError, error_regexp):
            # Should throw because the padding number is not non zero.
            IntegerKey("version_number", format_spec="00")

        with self.assertRaisesRegex(TankError, error_regexp):
            # Should throw because it is not a non zero positive integer
            IntegerKey("version_number", format_spec="0")

        with self.assertRaisesRegex(TankError, error_regexp):
            # Should throw because the padding caracter is invalid
            IntegerKey("version_number", format_spec="a0")

        with self.assertRaisesRegex(TankError, error_regexp):
            # Should throw because the padding size is not a number.
            IntegerKey("version_number", format_spec="0a")

    def test_no_format_spec(self):
        key = IntegerKey("version_number")
        key.value_from_str

    def _validate_key(self, key, strict_matching, format_spec):
        """
        Makes sure that an integer key's formatting options are correctly set.
        """
        self.assertEqual(key.strict_matching, strict_matching)
        self.assertEqual(key.format_spec, format_spec)

    def test_non_strict_matching(self):
        """
        In non strict mode, tokens can actually have less numbers than the padding requests. Also,
        if there are more, can also match.
        """
        self._test_non_strict_matching('0')
        self._test_non_strict_matching('')

    def _test_non_strict_matching(self, padding_char):
        """
        Allows to test strict matching with a specific padding character.

        :param padding_char: Character to test padding with. Should be space or 0.
        """
        key = IntegerKey("version_number", format_spec="%s3" % padding_char, strict_matching=False)

        # The padding char is missing in the format specifier, but we still need when validating
        # results.
        if padding_char == '':
            padding_char = ' '

        # It should match because they are valid numbers.

        self.assertEqual(key.value_from_str("000"), 0)
        self.assertEqual(key.value_from_str("0"), 0)
        self.assertEqual(key.value_from_str("0"), 0)

        # While the number doesn't make any sense as far as formatting is concerned, this used
        # to work in old versions of Toolkit and needs to keep working in non strict mode.
        self.assertEqual(key.value_from_str("%s000" % padding_char), 0)

        # It should match a template with too many digits...
        self.assertEqual(key.value_from_str("20000"), 20000)

        # ... even if they are all zeros because lossy matching.
        self.assertEqual(key.value_from_str("00000"), 0)

        # From path to tokens back to path should be lossy.
        value = key.value_from_str("1")
        self.assertEqual("%s%s1" % (padding_char, padding_char), key.str_from_value(value))

        self._test_nan(key, "expected an Integer")

    def _test_nan(self, key, error_msg):
        """
        Tests a key with against values that are not numbers.

        :param key: Key to test.
        :param error_msg: Text that partially matches the error message.
        """
        # Should fail because not a number
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("aaaa")
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("0a")
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("a0")
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("aa")

    def _test_strict_matching(self, padding_char):
        """
        Allows to test strict matching with any padding type.
        """
        # have a template that formats with two digits of padding.
        key = IntegerKey("version_number", format_spec="%s3" % padding_char, strict_matching=True)
        self.assertTrue(key.strict_matching)

        # The padding char is missing in the format specifier, but we still need when validating
        # results.
        if padding_char == '':
            padding_char = ' '

        # From path to tokens back to path should get back the same string when the expected number of
        # digits are found.
        value = key.value_from_str("%s%s1" % (padding_char, padding_char))
        self.assertEqual("%s%s1" % (padding_char, padding_char), key.str_from_value(value))

        # It should match a template with more digits.
        value = key.value_from_str("20000")
        self.assertEqual("20000", key.str_from_value(value))

        key.value_from_str("123")

        error_msg = "does not match format spec"

        # It should not match a string with too few digits
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("1")

        # It should not match a template with too many digits that are all zero because that would
        # lossy. (there are more zeros than the format spec can rebuild)
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("0000")

        # It should not match negative numbers either
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("-1000")

        # It should not match baddly padded numbers
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("0100")

        # It should not match negative values
        with self.assertRaisesRegex(TankError, error_msg):
            key.value_from_str("-01")

        self._test_nan(key, error_msg)

    def test_strict_matching(self):
        """
        In strict mode, tokens have to have as much padding as the format specifier suggests. Less will not
        match.
        """
        self._test_strict_matching('')
        self._test_strict_matching('0')