Verified Commit 1a61c3d1 authored by David Runge's avatar David Runge
Browse files

Add first validators to models

repo_management/models.py:
Add validators to the `BuildDate`, `CSize`, `ISize`, `Name` and
`Version` models to ensure positive integers, correct names and
versions.
Add the comparator instance methods `Version.is_older_than()` and
`Version.is_newer_than()` which rely on pyalpm's `vercmp()` to compare
two version strings and return whether they are older or newer
(respectively).
Update the documentation for `ISize` to reflect, that it represents size
of an installed package.

tests/test_models.py:
Add tests for added validators and comparator methods.
parent 64bd6e25
Pipeline #5872 passed with stage
in 6 minutes and 20 seconds
import io
from typing import List, Optional, Tuple
from pydantic import BaseModel
from pyalpm import vercmp
from pydantic import BaseModel, validator
from repo_management import defaults
......@@ -57,6 +58,13 @@ class BuildDate(BaseModel):
builddate: int
@validator("builddate")
def builddate_greater_zero(cls, builddate: int) -> int:
if builddate < 0:
raise ValueError("The build date must be greater than zero.")
return builddate
class CheckDepends(BaseModel):
"""A model describing a single 'checkdepends' attribute
......@@ -96,6 +104,13 @@ class CSize(BaseModel):
csize: int
@validator("csize")
def csize_greater_equal_zero(cls, csize: int) -> int:
if csize < 0:
raise ValueError("The csize must be greater than or equal zero.")
return csize
class Depends(BaseModel):
"""A model describing a single 'depends' attribute
......@@ -169,11 +184,18 @@ class ISize(BaseModel):
----------
isize: int
The attribute can be used to describe the (required) data below an %ISIZE% identifier in a 'desc' file, which
identifies a package's size
identifies a package's installed size
"""
isize: int
@validator("isize")
def isize_greater_equal_zero(cls, isize: int) -> int:
if isize < 0:
raise ValueError("The isize must be greater than or equal zero.")
return isize
class License(BaseModel):
"""A model describing a single 'license' attribute
......@@ -226,6 +248,26 @@ class Name(BaseModel):
name: str
@validator("name")
def name_contains_only_allowed_chars(cls, name: str) -> str:
disallowed_start_chars = [".", "-"]
for char in disallowed_start_chars:
if name.startswith(char):
raise ValueError(f"The package name '{name}' can not start with any of '{disallowed_start_chars}'.")
allowed_chars = ["@", ".", "_", "+", "-"]
remaining_chars: List[str] = []
for char in name:
if (not char.isalnum() or (not char.isdigit() and not char.islower())) and char not in allowed_chars:
remaining_chars += [char]
if remaining_chars:
raise ValueError(
f"The package name '{name}' can not contain '{remaining_chars}' but must consist only of alphanumeric "
f"chars and any of '{allowed_chars}'."
)
return name
class Packager(BaseModel):
"""A model describing a single 'packager' attribute
......@@ -343,6 +385,64 @@ class Version(BaseModel):
version: str
@validator("version")
def version_is_valid(cls, version: str) -> str:
allowed_chars = [":", ".", "_", "+", "-"]
if version.endswith("-0"):
raise ValueError("The first pkgrel of a package release always needs to start at 1.")
for char in allowed_chars:
if version.startswith(char):
raise ValueError("The first character of a package version must not be '{char}'.")
remaining_chars: List[str] = []
for char in version:
if not char.isalnum() and char not in allowed_chars:
remaining_chars += [char]
if remaining_chars:
raise ValueError(
f"Package versions can not contain '{remaining_chars}' but must consist of alphanumeric chars and any "
f"of '{allowed_chars}'."
)
return version
def is_older_than(self, version: str) -> bool:
"""Check whether the version is older than a provided version
Parameters
----------
version: str
Another version string to compare that of self to
Returns
-------
True if self.version is older than the provided version, False otherwise.
"""
if vercmp(self.version, version) < 0:
return True
else:
return False
def is_newer_than(self, version: str) -> bool:
"""Check whether the version is newer than a provided version
Parameters
----------
version: str
Another version string to compare that of self to
Returns
-------
True if self.version is newer than the provided version, False otherwise.
"""
if vercmp(self.version, version) > 0:
return True
else:
return False
class OutputPackage(
Arch,
......@@ -406,7 +506,7 @@ class OutputPackage(
identifies a package's groups
isize: int
The attribute can be used to describe the (required) data below an %ISIZE% identifier in a 'desc' file, which
identifies a package's size
identifies a package's installed size
license: List[str]
The attribute can be used to describe the (required) data below a %LICENSE% identifier in a 'desc' file, which
identifies a package's license(s)
......@@ -504,7 +604,7 @@ class PackageDesc(
identifies a package's groups
isize: int
The attribute can be used to describe the (required) data below an %ISIZE% identifier in a 'desc' file, which
identifies a package's size
identifies a package's installed size
license: List[str]
The attribute can be used to describe the (required) data below a %LICENSE% identifier in a 'desc' file, which
identifies a package's license(s)
......
from typing import List, Optional, Tuple
from contextlib import nullcontext as does_not_raise
from typing import ContextManager, List, Optional, Tuple
from pytest import mark
from pytest import mark, raises
from repo_management import models
......@@ -143,3 +144,97 @@ def test_output_package_base_get_packages_as_models(
output_package_base: models.OutputPackageBase,
) -> None:
assert models_list == output_package_base.get_packages_as_models()
@mark.parametrize(
"name, expectation",
[
(".foo", raises(ValueError)),
("-foo", raises(ValueError)),
("foo'", raises(ValueError)),
("foo", does_not_raise()),
],
)
def test_name(name: str, expectation: ContextManager[str]) -> None:
with expectation:
assert name == models.Name(name=name).name
@mark.parametrize(
"builddate, expectation",
[
(-1, raises(ValueError)),
(1, does_not_raise()),
],
)
def test_builddate(builddate: int, expectation: ContextManager[str]) -> None:
with expectation:
assert builddate == models.BuildDate(builddate=builddate).builddate
@mark.parametrize(
"csize, expectation",
[
(-1, raises(ValueError)),
(1, does_not_raise()),
],
)
def test_csize(csize: int, expectation: ContextManager[str]) -> None:
with expectation:
assert csize == models.CSize(csize=csize).csize
@mark.parametrize(
"isize, expectation",
[
(-1, raises(ValueError)),
(1, does_not_raise()),
],
)
def test_isize(isize: int, expectation: ContextManager[str]) -> None:
with expectation:
assert isize == models.ISize(isize=isize).isize
@mark.parametrize(
"version, expectation",
[
("1.2.3-0", raises(ValueError)),
(".1.2.3-1", raises(ValueError)),
("-1.2.3-1", raises(ValueError)),
(":1.2.3-1", raises(ValueError)),
("_1.2.3-1", raises(ValueError)),
("+1.2.3-1", raises(ValueError)),
("1.2.'3-1", raises(ValueError)),
("1.2.3-1", does_not_raise()),
("1:1.2.3-1", does_not_raise()),
("1:1.2.3r500.x.y.z.1-1", does_not_raise()),
],
)
def test_version_version_is_valid(version: str, expectation: ContextManager[str]) -> None:
with expectation:
assert version == models.Version(version=version).version
@mark.parametrize(
"version, other_version, expectation",
[
("1.2.3-1", "1.2.3-2", True),
("1.2.3-2", "1.2.3-1", False),
],
)
def test_version_is_older_than(version: str, other_version: str, expectation: bool) -> None:
model = models.Version(version=version)
assert model.is_older_than(other_version) is expectation
@mark.parametrize(
"version, other_version, expectation",
[
("1.2.3-1", "1.2.3-2", False),
("1.2.3-2", "1.2.3-1", True),
],
)
def test_version_is_newer_than(version: str, other_version: str, expectation: bool) -> None:
model = models.Version(version=version)
assert model.is_newer_than(other_version) is expectation
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment