Skip to content

Instantly share code, notes, and snippets.

@ByteJuggler
Last active October 1, 2016 14:31
Show Gist options
  • Save ByteJuggler/f35154f9584d7cbd65afb89ffc2691f1 to your computer and use it in GitHub Desktop.
Save ByteJuggler/f35154f9584d7cbd65afb89ffc2691f1 to your computer and use it in GitHub Desktop.
Py.Test test cases for email validation (& CodeEval challenge 35)
#!/usr/bin/env python
# -*- coding: windows-1252 -*-
# Copyright © 2016 Walter Prins. All rights reserved.
# Created: 2016-10-01
# Updated: 2016-10-01
"""Test cases for a hypothetical module called "email_validation" and a Python
callable (class) that will tell you if a given email is valid or not. My own
implementation is ultimately based on the RFC's and a state machine,
and passes against the below test suite. It also passes the CodeEval challenge
below (a question about which prodded me into having a look at this in the
first place):
https://www.codeeval.com/open_challenges/35/
Note: The additional output e.g. "resultcode", "invalidchar" and "invalidpos"
is not required by the challenge, I've added it because my implementation
is based on an earlier Object Pascal implementation that similarly provides
more information than just a true/false output. Hence I therefore wanted to keep
it around for fun and profit in my Python implementation as well, and also
thought it would be fun to write a Python solution that seamlessly can work
for the CodeEval challenge API,and yet also retains the higher fidelity feedback
if you want it (telling you what's actually wrong), if desired.
If however these extra properties/members give you a headache and
you just want to use these tests to help your development for the above
challenge, then obviously please rip them out and keep only the bool checks!
"""
from email_validation import email_valid, ResultCode
def testAllowBlankProperty():
"""In my class I allow the caller to specify whether they'd like to consider
a blank email as valid or not. Check that this works"""
result = email_valid('', True)
assert result == True
assert result.resultcode == ResultCode.EmailValid
assert result.invalidchar == None
assert result.invalidpos == None
result = email_valid('', False)
assert result == False
assert result.resultcode == ResultCode.BlankAddressNotAllowed
assert result.invalidchar == None
assert result.invalidpos == 0
def testQuotedWSpaceNameEmail():
"""Emails can contain space in the name part, provided they're quoted."""
result = email_valid('"joe bloggs"@b.c')
assert result == True
assert result.resultcode == ResultCode.EmailValid
result = email_valid('joe bloggs@b.c')
assert result == False
assert result.resultcode == ResultCode.InvalidCharacter
assert result.invalidchar == ' '
assert result.invalidpos == 3
def testShortestPossibleEmail():
"""Emails have to have at least 2 subdomain parts, so this corresponds to
the shortest email address that is valid."""
result = email_valid('a@b.c')
assert result == True
assert result.resultcode == ResultCode.EmailValid
assert result.invalidchar == None
assert result.invalidpos == None
def testBadlyTerminatedEmail():
"""Here's several inputs that constitute partially valid or badly terminated
email addresses. E.g. Either they're incomplete, or they've been badly
terminated, either way they're not valid as-is."""
# Email cannot terminate on a period
result = email_valid('a@b.c.')
assert result == False
assert result.resultcode == ResultCode.EmailIncompleteOrBadlyTerminated
assert result.invalidchar == None
#We expect the call to tell us that the last character is where the problem
#occurs, even though it's not actually invalid:
#(One might equally design the call/library to not do this... wouldn't have
# too many arguments from me if you preferred it the other way, e.g.
# always have invalidpos None unless invalidchar is not None also... still
# as of this writing I thought this would be more informative so there you
# go.
assert result.invalidpos == 5
# Email cannot terminate on a hyphen
result = email_valid('a@b.c-')
assert result == False
assert result.resultcode == ResultCode.EmailIncompleteOrBadlyTerminated
assert result.invalidchar == None
assert result.invalidpos == 5
# ... likewise double hyphen is invalid.
result = email_valid('a@b.c--')
assert result == False
assert result.resultcode == ResultCode.EmailIncompleteOrBadlyTerminated
assert result.invalidchar == None
assert result.invalidpos == 6
# Some further test cases that break some other validators.
# Can't terminate on second @, it is outright not valid.
result = email_valid('a@b.c@')
assert result == False
assert result.resultcode == ResultCode.InvalidCharacter
assert result.invalidchar == '@'
assert result.invalidpos == 5
# Can't terminate on space, it is outright not valid.
result = email_valid('a@b.c ')
assert result == False
assert result.resultcode == ResultCode.InvalidCharacter
assert result.invalidchar == ' '
assert result.invalidpos == 5
def testTooShortEmail():
"""Test that too short emails are caught appropriately."""
result = email_valid('a@b')
assert result == False
assert result.resultcode == ResultCode.EmailMustHave2SubDomains
assert result.invalidchar == None
assert result.invalidpos == None
def testQuotedWSpaceSubdomainEmail():
"""Subdomains may not contain spaces, even if quoted."""
result = email_valid('a@"my company".c')
assert result == False
assert result.resultcode == ResultCode.InvalidCharacter
assert result.invalidchar == '"'
assert result.invalidpos == 2
def testHyphenatedEmail():
"""Various test cases with hyphens that trip up some validators but are
in fact valid email addresses and should be allowed:"""
result = email_valid('a-b@b.c')
assert result == True
assert result.resultcode == ResultCode.EmailValid
assert result.invalidchar == None
assert result.invalidpos == None
result = email_valid('a@b-c.d')
assert result == True
assert result.resultcode == ResultCode.EmailValid
assert result.invalidchar == None
assert result.invalidpos == None
result = email_valid('a@b--c.d')
assert result == True
assert result.resultcode == ResultCode.EmailValid
assert result.invalidchar == None
assert result.invalidpos == None
result = email_valid('a-@b.c')
assert result == True
assert result.resultcode == ResultCode.EmailValid
assert result.invalidchar == None
assert result.invalidpos == None
def testUnderscoredEmail():
"""Various test cases with underscores that trip up some validators.
Some valid, some not."""
result = email_valid('a_b@b.c')
assert result == True
assert result.resultcode == ResultCode.EmailValid
assert result.invalidchar == None
assert result.invalidpos == None
result = email_valid('a@b_c.d')
assert result == False
assert result.resultcode == ResultCode.InvalidCharacter
assert result.invalidchar == '_'
assert result.invalidpos == 3
result = email_valid('a_@b.c')
assert result == True
assert result.resultcode == ResultCode.EmailValid
assert result.invalidchar == None
assert result.invalidpos == None
def test_CodeEval_Cases():
result = email_valid('foo@bar.com')
assert result == True
assert result.resultcode == ResultCode.EmailValid
assert result.invalidchar == None
assert result.invalidpos == None
result = email_valid('this is not an email id')
assert result == False
assert result.resultcode == ResultCode.InvalidCharacter
assert result.invalidchar == ' '
assert result.invalidpos == 4
result = email_valid('admin#codeeval.com')
assert result == False
assert result.resultcode == ResultCode.EmailIncompleteOrBadlyTerminated
assert result.invalidchar == None
assert result.invalidpos == 17
result = email_valid('good123@bad.com')
assert result == True
assert result.resultcode == ResultCode.EmailValid
assert result.invalidchar == None
assert result.invalidpos == None
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment