Created
January 4, 2022 23:40
-
-
Save twolfson/7fdb6045f5974411f0ef196160414ea6 to your computer and use it in GitHub Desktop.
Tipalti API name support via fuzzing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Last updated: 2022-01-04 | |
def is_valid_tipalti_name(name): | |
# https://support.tipalti.com/Content/Topics/Development/APIs/PayeeAPI/UpdatePayee/CreatePayeeInfoAutoIdap/Intro.htm#PayeeDetailsItem1 | |
# Max length: 70 -- Incorrect: During testing it's 35 characters... | |
# Latin and numeric (cannot be only numeric) | |
# Spaces, periods, dashes (cannot be the first character)—e.g., "Mary Jo", "Jr.", "Mary-Jo" | |
# We've found additional cases like "Test 4" which fail, see tests for robust overview | |
# Their API truncates names at 35 characters | |
# This is fine for our use case and we won't reject a name for being too long | |
# If we contain any unexpected characters, reject it | |
if re.search(r'[^A-Za-z -\.]', name): | |
return False | |
# Split up our name into words, filter out empty ones | |
words = name.split(' ') | |
words = [word for word in words if word] | |
# If we have no words, stop (means was empty string or only spaces) | |
if not words: | |
return False | |
# Validate each word | |
for word in words: | |
if word[0] in ['-', '.'] or word[-1] in ['-']: | |
return False | |
# DEV: We won't run into an IndexError as that implies the word was only '.', which is covered by last `if` | |
if word.rstrip('.')[-1] in ['-']: | |
return False | |
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Last updated: 2022-01-04 | |
class TipaltiUtilsTestCase(TestCase): | |
def test_is_valid_tipalti_name(self): | |
"""Verify is_valid_tipalti_name lines up to API expectations""" | |
# Sanity checked directly via API calls | |
# Basic test case | |
self.assertEqual(is_valid_tipalti_name('foo'), True) | |
# Numbers disallowed in all forms - docs say valid, reality says no | |
self.assertEqual(is_valid_tipalti_name('1'), False) | |
self.assertEqual(is_valid_tipalti_name('foo4'), False) | |
self.assertEqual(is_valid_tipalti_name('foo4bar'), False) | |
# Dealing with spaces | |
self.assertEqual(is_valid_tipalti_name('foo bar'), True) | |
self.assertEqual(is_valid_tipalti_name('foo '), True) # Truncated to 'foo', which is valid | |
self.assertEqual(is_valid_tipalti_name('foo '), True) # Truncated to 'foo', which is valid | |
self.assertEqual(is_valid_tipalti_name(' '), False) # Truncated to '', which is technically valid but not for us | |
# Disallowed characters | |
self.assertEqual(is_valid_tipalti_name('föo'), False) | |
# Excepted characters (already dealt with spaces in isolation) | |
self.assertEqual(is_valid_tipalti_name('foo-'), False) # Docs say valid, reality says no | |
self.assertEqual(is_valid_tipalti_name('foo -'), False) | |
self.assertEqual(is_valid_tipalti_name('foo - bar'), False) | |
self.assertEqual(is_valid_tipalti_name('foo-bar'), True) | |
self.assertEqual(is_valid_tipalti_name('foo -bar'), False) | |
self.assertEqual(is_valid_tipalti_name('foo.'), True) | |
self.assertEqual(is_valid_tipalti_name('foo.bar'), True) | |
self.assertEqual(is_valid_tipalti_name('foo .bar'), False) | |
self.assertEqual(is_valid_tipalti_name('foo-.'), False) # Fun edge case | |
self.assertEqual(is_valid_tipalti_name('foo-bar.'), True) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment