Coverage for tests/factories.py: 100%
36 statements
« prev ^ index » next coverage.py v7.10.3, created at 2026-08-22 19:08 +0000
« prev ^ index » next coverage.py v7.10.3, created at 2026-08-22 19:08 +0000
1"""Polyfactory factories for the public data model.
3They keep property style tests honest: instead of hand writing a handful of settings objects we let
4polyfactory build many of them, with the ranges narrowed to values that make sense for a parser.
5"""
7import random
8import typing
10from polyfactory.factories import dataclass_factory
12from meta_tags_parser import structs
15FACTORY_RANDOM_SEED: typing.Final = 20260818
16MAX_GENERATED_LIMIT_CHARS: typing.Final = 8192
17MIN_GENERATED_LIMIT_CHARS: typing.Final = 16
18SHARED_RANDOM_SOURCE: typing.Final = random.Random(FACTORY_RANDOM_SEED)
19KNOWN_BOUNDARY_TAG_PAIRS: typing.Final[tuple[tuple[str, str], ...]] = (
20 ("</head>", "<body"),
21 ("</HEAD>", "<BODY"),
22 ("</head>", "<article"),
23 ("</title>", "<body"),
24)
27@typing.final
28class OneMetaTagFactory(dataclass_factory.DataclassFactory[structs.OneMetaTag]):
29 """Build arbitrary meta tags with names that look like the ones sites really ship."""
31 __model__ = structs.OneMetaTag
32 __random__ = SHARED_RANDOM_SOURCE
34 @classmethod
35 def name(cls) -> str: # noqa: COP009, COP007
36 return cls.__random__.choice(("title", "description", "image", "image:width", "image:height", "url", "audio"))
39@typing.final
40class SettingsFromUserFactory(dataclass_factory.DataclassFactory[structs.SettingsFromUser]):
41 """Build settings objects covering every combination of what_to_parse and slicing limits."""
43 __model__ = structs.SettingsFromUser
44 __random__ = SHARED_RANDOM_SOURCE
46 @classmethod
47 def what_to_parse(cls) -> tuple[structs.WhatToParse, ...]: # noqa: COP009, COP007
48 possible_parts: typing.Final[list[structs.WhatToParse]] = list(structs.WhatToParse)
49 return tuple(cls.__random__.sample(possible_parts, k=cls.__random__.randint(1, len(possible_parts))))
51 @classmethod
52 def boundary_tags(cls) -> tuple[str, str]: # noqa: COP009, COP007
53 return cls.__random__.choice(KNOWN_BOUNDARY_TAG_PAIRS)
55 @classmethod
56 def fallback_limit_chars(cls) -> int: # noqa: COP009, COP007
57 return cls.__random__.randint(MIN_GENERATED_LIMIT_CHARS, MAX_GENERATED_LIMIT_CHARS)
59 @classmethod
60 def max_scan_chars(cls) -> int: # noqa: COP009, COP007
61 return cls.__random__.randint(MIN_GENERATED_LIMIT_CHARS, MAX_GENERATED_LIMIT_CHARS)
63 @classmethod
64 def hard_limit_chars(cls) -> int | None: # noqa: COP009, COP007
65 return cls.__random__.choice(
66 (None, cls.__random__.randint(MIN_GENERATED_LIMIT_CHARS, MAX_GENERATED_LIMIT_CHARS))
67 )