Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ajustando metodo is_valid como único #260

Merged
merged 2 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions brutils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@
format as format_license_plate,
get_format as get_license_plate_format,
is_valid as is_valid_license_plate,
is_valid_old_format as is_valid_license_plate_old_format,
is_valid_mercosul as is_valid_license_plate_mercosul,
remove_symbols as remove_symbols_license_plate,
)

Expand Down
125 changes: 44 additions & 81 deletions brutils/license_plate.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ def convert_to_mercosul(license_plate: str) -> Optional[str]:
>>> convert_to_mercosul("ABC4*67")
None
"""

if not is_valid_old_format(license_plate):
if not _is_valid_old_format(license_plate):
return None

digits = [letter for letter in license_plate.upper()]
Expand Down Expand Up @@ -58,11 +57,9 @@ def format(license_plate: str) -> Optional[str]:
"""

license_plate = license_plate.upper()

if is_valid_old_format(license_plate):
if _is_valid_old_format(license_plate):
return license_plate[0:3] + "-" + license_plate[3:]

if is_valid_mercosul(license_plate):
elif _is_valid_mercosul(license_plate):
return license_plate.upper()

return None
Expand All @@ -72,89 +69,30 @@ def format(license_plate: str) -> Optional[str]:
############


def is_valid(license_plate: str) -> bool:
def is_valid(license_plate, type=None): # type: (str, str) -> bool
"""
Check if a license plate is valid.
This function does not verify if the license plate is a real license plate;
it only validates the format of the string.
Returns if a Brazilian license plate number is valid.
It does not verify if the plate actually exists.

Args:
license_plate (str): A license plate string.

license_plate (str): The licence plate number to validate.
Only digits.
type (str): "old_format" or "mercosul".
If not specified, checks for one or another.
Returns:
bool: True if the license plate is valid, False otherwise.

Example:
>>> is_valid('def5678')
True
>>> is_valid('abc1e67')
True
>>> is_valid('abe67')
False
"""

return is_valid_old_format(license_plate) or is_valid_mercosul(
license_plate
)


def is_valid_old_format(license_plate: str) -> bool:
bool: True if the plate number is valid. False otherwise.
"""
Checks whether a string matches the old format of Brazilian license plate
(LLLNNNN).
This function does not verify if the license plate is a real license plate;
it only validates the format of the string.

Args:
license_plate (str): A license plate string.

Returns:
bool: True if the string corresponds to a license plate in the old
pattern format, False otherwise.

Example:
>>> is_valid_old_format('def5678')
True
>>> is_valid_old_format('GHI-4567')
False
"""
if type == "old_format":
return _is_valid_old_format(license_plate)
if type == "mercosul":
return _is_valid_mercosul(license_plate)

pattern = re.compile(r"^[A-Za-z]{3}[0-9]{4}$")
return (
isinstance(license_plate, str)
and re.match(pattern, license_plate.strip()) is not None
return _is_valid_old_format(license_plate) or _is_valid_mercosul(
license_plate
)


def is_valid_mercosul(license_plate: str) -> bool:
"""
Checks whether a string matches the Mercosul license plate format (LLLNNNN).
This function does not verify if the license plate is a real license plate;
it only validates the format of the string.

Args:
license_plate (str): A license plate string.

Returns:
bool: True if the string corresponds to a license plate in the Mercosul
pattern format, False otherwise.

Example:
>>> is_valid_mercosul('abc4e67')
True
>>> is_valid_mercosul('abc167')
False
"""

if not isinstance(license_plate, str):
return False

license_plate = license_plate.upper().strip()
pattern = re.compile(r"^[A-Z]{3}\d[A-Z]\d{2}$")

return re.match(pattern, license_plate) is not None


def remove_symbols(license_plate_number: str) -> str:
"""
Removes the dash (-) symbol from a license plate string.
Expand Down Expand Up @@ -199,10 +137,10 @@ def get_format(license_plate: str) -> Optional[str]:
None
"""

if is_valid_old_format(license_plate):
if _is_valid_old_format(license_plate):
return "LLLNNNN"

if is_valid_mercosul(license_plate):
if _is_valid_mercosul(license_plate):
return "LLLNLNN"

return None
Expand Down Expand Up @@ -247,3 +185,28 @@ def generate(format="LLLNLNN"): # type: (str) -> str | None
generated += str(randint(0, 9))

return generated


def _is_valid_old_format(license_plate: str) -> bool:
"""
Checks whether a string matches the old format of Brazilian license plate.
"""
pattern = re.compile(r"^[A-Za-z]{3}[0-9]{4}$")
return (
isinstance(license_plate, str)
and re.match(pattern, license_plate.strip()) is not None
)


def _is_valid_mercosul(license_plate: str) -> bool:
"""
Returns whether or not the provided license_plate is valid according to the
Mercosul pattern (LLLNLNN). Input should be a digit string of proper
length. Ex: ABC4E67
"""
if not isinstance(license_plate, str):
return False

license_plate = license_plate.upper().strip()
pattern = re.compile(r"^[A-Z]{3}\d[A-Z]\d{2}$")
return re.match(pattern, license_plate) is not None
6 changes: 3 additions & 3 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Empty file.
151 changes: 151 additions & 0 deletions tests/license_plate/test_is_valid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
from brutils.license_plate import (
_is_valid_mercosul,
_is_valid_old_format,
is_valid,
)
from unittest.mock import patch
from unittest import TestCase, main


class TestLicensePlate(TestCase):
@patch("brutils.license_plate._is_valid_mercosul")
@patch("brutils.license_plate._is_valid_old_format")
class TestIsValid:
class TestTypeOldFormat:
def test_when_old_format_is_valid_returns_true(
self, mock__is_valid_old_format, mock__is_valid_mercosul
):
mock__is_valid_old_format.return_value = True

self.assertIs(is_valid("ABC1234", "old_format"), True)
mock__is_valid_old_format.assert_called_once_with("ABC1234")
mock__is_valid_mercosul.assert_not_called()

def test_when_old_format_is_not_valid_returns_false(
self, mock__is_valid_old_format, mock__is_valid_mercosul
):
mock__is_valid_old_format.return_value = False

self.assertIs(is_valid("123456", "old_format"), False)
mock__is_valid_old_format.assert_called_once_with("123456")
mock__is_valid_mercosul.assert_not_called()

class TestTypeMercosul:
def test_when_mercosul_is_valid_returns_true(
self, mock__is_valid_old_format, mock__is_valid_mercosul
):
mock__is_valid_mercosul.return_value = True

self.assertIs(is_valid("ABC4E67", "mercosul"), True)
mock__is_valid_mercosul.assert_called_once_with("ABC4E67")
mock__is_valid_old_format.assert_not_called()

def test_when_mercosul_is_not_valid_returns_false(
self, mock__is_valid_old_format, mock__is_valid_mercosul
):
mock__is_valid_mercosul.return_value = False

self.assertIs(is_valid("11994029275", "mercosul"), False)
mock__is_valid_mercosul.assert_called_once_with("11994029275")
mock__is_valid_old_format.assert_not_called()

class TestTypeNone:
def test_when_mercosul_valid_old_format_invalid(
self, mock__is_valid_old_format, mock__is_valid_mercosul
):
mock__is_valid_mercosul.return_value = True
mock__is_valid_old_format.return_value = False

self.assertTrue(is_valid("ABC4E67"))
mock__is_valid_mercosul.assert_called_once_with("ABC4E67")
mock__is_valid_old_format.assert_not_called()

def test_when_mercosul_and_old_format_are_valids(
self, mock__is_valid_old_format, mock__is_valid_mercosul
):
mock__is_valid_mercosul.return_value = True
mock__is_valid_old_format.return_value = True

self.assertIs(is_valid("ABC1234"), True)
mock__is_valid_mercosul.assert_called_once_with("ABC4E67")
mock__is_valid_old_format.assert_called_once_with("ABC1234")

def test_when_mercosul_invalid_old_format_valid(
self, mock__is_valid_old_format, mock__is_valid_mercosul
):
mock__is_valid_old_format.return_value = True
mock__is_valid_mercosul.return_value = False

self.assertIs(is_valid("ABC1234"), True)
mock__is_valid_old_format.assert_called_once_with("ABC1234")
mock__is_valid_mercosul.assert_not_called("ABC4E67")

def test_when_mercosul_and_old_format_are_invalid(
self, mock__is_valid_old_format, mock__is_valid_mercosul
):
mock__is_valid_old_format.return_value = False
mock__is_valid_mercosul.return_value = False

self.assertIs(is_valid("ABC1234"), False)
mock__is_valid_old_format.assert_called_once_with("ABC1234")
mock__is_valid_mercosul.assert_called_once_with("ABC4E67")

class TestIsValidOldFormat:
def test__is_valid_old_format(self):
# When license plate is valid, returns True
self.assertTrue(_is_valid_old_format("ABC1234"))
self.assertTrue(_is_valid_old_format("abc1234"))

# When license plate is valid with whitespaces, returns True
self.assertTrue(_is_valid_old_format(" ABC1234 "))

# When license plate is not string, returns False
self.assertFalse(_is_valid_old_format(123456))

# When license plate is invalid with special characters,
# returns False
self.assertFalse(_is_valid_old_format("ABC-1234"))

# When license plate is invalid with numbers and letters out of
# order, returns False
self.assertFalse(_is_valid_old_format("A1CA23W"))

# When license plate is invalid with new format, returns False
self.assertFalse(_is_valid_old_format("ABC1D23"))
self.assertFalse(_is_valid_old_format("abcd123"))

class TestIsValidMercosul:
def test__is_valid_mercosul(self):
# When license plate is not string, returns False
self.assertIs(_is_valid_mercosul(1234567), False)

# When license plate doesn't match the pattern LLLNLNN,
# returns False
self.assertIs(_is_valid_mercosul("ABCDEFG"), False)
self.assertIs(_is_valid_mercosul("1234567"), False)
self.assertIs(_is_valid_mercosul("ABC4567"), False)
self.assertIs(_is_valid_mercosul("ABCD567"), False)
self.assertIs(_is_valid_mercosul("ABC45F7"), False)
self.assertIs(_is_valid_mercosul("ABC456G"), False)
self.assertIs(_is_valid_mercosul("ABC123"), False)

# When license plate is an empty string, returns False
self.assertIs(_is_valid_mercosul(""), False)

# When license plate's length is different of 7, returns False
self.assertIs(_is_valid_mercosul("ABC4E678"), False)

# When license plate has separator, returns false
self.assertIs(_is_valid_mercosul("ABC-1D23"), False)

# When license plate is valid
self.assertIs(_is_valid_mercosul("ABC4E67"), True)
self.assertIs(_is_valid_mercosul("AAA1A11"), True)
self.assertIs(_is_valid_mercosul("XXX9X99"), True)

# Check if function is case insensitive
self.assertIs(_is_valid_mercosul("abc4e67"), True)


if __name__ == "__main__":
main()
Loading