Skip to content

Instantly share code, notes, and snippets.

@twolfson
Created January 4, 2022 23:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save twolfson/7fdb6045f5974411f0ef196160414ea6 to your computer and use it in GitHub Desktop.
Save twolfson/7fdb6045f5974411f0ef196160414ea6 to your computer and use it in GitHub Desktop.
Tipalti API name support via fuzzing
# 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
# 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