Skip to content

Commit c986c9e

Browse files
committed
Add is_valid_string method to Version class for version string validation
1 parent 79dd493 commit c986c9e

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

version/tests/version_tests.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,3 +489,68 @@ def test_from_string_4_digits_with_metadata():
489489
assert version.patch == 3
490490
assert version.prerelease == "4"
491491
assert version.metadata == "build.1"
492+
493+
@pytest.mark.parametrize(
494+
"version_str,expected",
495+
[
496+
# Happy path: 3-digit version
497+
("1.2.3", True),
498+
# Happy path: 4-digit version
499+
("1.2.3.4", True),
500+
# Happy path: large numbers
501+
("123.456.789", True),
502+
("123.456.789.0", True),
503+
# Edge: single digit
504+
("0.0.0", True),
505+
("0.0.0.0", True),
506+
# Edge: leading zeros
507+
("01.02.03", True),
508+
("01.02.03.04", True),
509+
# Error: too few digits
510+
("1.2", False),
511+
("1", False),
512+
# Happy path: 5-digit version with the last 2 parts as prerelease (4.5)
513+
("1.2.3.4.5", True),
514+
# Error: non-numeric
515+
("a.b.c", False),
516+
("1.2.x", False),
517+
# Error: empty string
518+
("", False),
519+
# Error: whitespace only
520+
(" ", False),
521+
# Error: whitespace around valid version
522+
(" 1.2.3 ", False),
523+
# Happy path: prerelease
524+
("1.2.3-beta", True),
525+
("v1.2.3", False)
526+
],
527+
ids=[
528+
"valid_3_digit",
529+
"valid_4_digit",
530+
"valid_large_3_digit",
531+
"valid_large_4_digit",
532+
"valid_zero_3_digit",
533+
"valid_zero_4_digit",
534+
"valid_leading_zero_3_digit",
535+
"valid_leading_zero_4_digit",
536+
"too_few_digits_2",
537+
"too_few_digits_1",
538+
"too_many_parts",
539+
"non_numeric",
540+
"non_numeric_last",
541+
"empty_string",
542+
"whitespace_only",
543+
"whitespace_around_valid",
544+
"valid_prerelease",
545+
"special_characters_v"
546+
]
547+
)
548+
def test_is_valid_string(version_str, expected):
549+
# Arrange
550+
# (No arrange needed if all inputs are parameters, except for None case)
551+
print(f"Testing version string: {version_str} : expected: {expected}")
552+
result = Version.is_valid_string(version_str)
553+
if result:
554+
print(repr(Version.from_string(version_str)))
555+
# Assert
556+
assert result == expected

version/version/version.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,16 @@ def from_string(cls, version_str: str):
144144

145145
return cls(major, minor, patch, prerelease, metadata)
146146

147+
@classmethod
148+
def is_valid_string(cls, version_str: str) -> bool:
149+
"""
150+
Check if a version string is valid.
151+
152+
:param version_str: Version string
153+
:return: True if valid, False otherwise
154+
"""
155+
return bool(cls._RE_VERSION.match(version_str)) or bool(cls._RE_4_DIGITS_VERSION.match(version_str))
156+
147157
def __str__(self) -> str:
148158
"""
149159
Return the version as a string.

0 commit comments

Comments
 (0)