Coverage for tests/conftest.py: 100%

49 statements  

« prev     ^ index     » next       coverage.py v7.10.3, created at 2026-08-22 19:08 +0000

1import dataclasses 

2import pathlib 

3import typing 

4 

5import hypothesis 

6import pytest 

7from faker import Faker 

8 

9from meta_tags_parser import parse, structs 

10 

11 

12FIXTURES_DIRECTORY: typing.Final = pathlib.Path(__file__).parent / "html_fixtures" 

13DETERMINISTIC_SEED: typing.Final = 20260818 

14HYPOTHESIS_PROFILE_NAME: typing.Final = "meta-tags-parser" 

15POSSIBLE_OG_TAGS_VALUES: typing.Final[tuple[str, ...]] = ( 

16 "title", 

17 "url", 

18 "image", 

19 "type", 

20 "description", 

21 "locale", 

22 "site_name", 

23 "video", 

24) 

25EXTRA_OTHER_TAG_NAMES: typing.Final[tuple[str, ...]] = ("article:name", "article:description") 

26REPEATED_TAG_LIMIT: typing.Final = 5 

27 

28 

29# parsing multi megabyte fixtures is slower than the hypothesis default deadline allows, 

30# and a deadline makes property tests flaky on loaded CI runners 

31hypothesis.settings.register_profile(HYPOTHESIS_PROFILE_NAME, deadline=None, print_blob=True) 

32hypothesis.settings.load_profile(HYPOTHESIS_PROFILE_NAME) 

33 

34 

35@typing.final 

36@dataclasses.dataclass(kw_only=True, slots=True, frozen=True) 

37class FakeMetaPage: 

38 """Randomly generated page together with what the parser must find inside it.""" 

39 

40 html_source: str 

41 social_tag_values: typing.Mapping[str, str] 

42 other_tag_names: tuple[str, ...] 

43 

44 

45@pytest.fixture(name="faker_seed", autouse=True) 

46def provide_faker_seed() -> int: 

47 """Keep faker output reproducible, a failing test must be replayable.""" 

48 return DETERMINISTIC_SEED 

49 

50 

51@pytest.fixture(autouse=True) 

52def restore_global_settings() -> typing.Iterator[None]: 

53 """Undo whatever set_settings_for_meta_tags did inside a test.""" 

54 yield 

55 parse.set_settings_for_meta_tags(structs.DEFAULT_SETTINGS_FROM_USER) 

56 

57 

58def _build_tag_content(faker: Faker, one_name: str) -> str: 

59 if one_name in ("url", "video"): 

60 return str(faker.url()) 

61 if one_name == "image": 

62 return str(faker.image_url()) 

63 return str(faker.text()) 

64 

65 

66@pytest.fixture 

67def provide_fake_meta_page(faker: Faker) -> FakeMetaPage: 

68 """Generate a random page with known Open Graph, Twitter, basic and other tags.""" 

69 markup_buffer: typing.Final[list[str]] = [ 

70 f"""<meta name="{one_name}" content="{faker.text()}">""" for one_name in structs.BASIC_META_TAGS 

71 ] 

72 social_tag_values: typing.Final[dict[str, str]] = {} 

73 for one_name in POSSIBLE_OG_TAGS_VALUES: 

74 for _ in range(faker.random_int(min=1, max=REPEATED_TAG_LIMIT)): 

75 tag_content: str = _build_tag_content(faker, one_name) 

76 markup_buffer.append(f"""<meta property="og:{one_name}" content="{tag_content}">""") 

77 markup_buffer.append(f"""<meta name="twitter:{one_name}" content="{tag_content}">""") 

78 social_tag_values[one_name] = tag_content 

79 markup_buffer.append(f"<title>{faker.text()}</title>") 

80 markup_buffer.extend(f"""<meta name="{one_name}" content="{faker.text()}">""" for one_name in EXTRA_OTHER_TAG_NAMES) 

81 markup_buffer.append("""<meta name="bad-tag">""") 

82 markup_buffer.append("""<meta property="another-bad-tag">""") 

83 return FakeMetaPage( 

84 html_source=("\n \t" * faker.random_int(min=1, max=REPEATED_TAG_LIMIT)).join(markup_buffer), 

85 social_tag_values=social_tag_values, 

86 other_tag_names=EXTRA_OTHER_TAG_NAMES, 

87 ) 

88 

89 

90@pytest.fixture 

91def provide_html_file_paths() -> list[pathlib.Path]: 

92 """Return the real captured pages shipped with the repository.""" 

93 return sorted(FIXTURES_DIRECTORY.glob("*.html"))