Coverage for tests/test_dict_views.py: 100%

53 statements  

« prev     ^ index     » next       coverage.py v7.10.4, created at 2025-08-21 23:45 +0000

1import importlib 

2import typing 

3 

4import pytest 

5from fastapi.testclient import TestClient 

6 

7from whole_app import models, views 

8from whole_app.settings import SETTINGS, StorageProviders 

9 

10 

11DICT_ENDPOINT: typing.Final = f"{SETTINGS.api_prefix}/dictionaries/" 

12 

13 

14class TestFileAndDummyBasedDicts: 

15 @pytest.fixture(params=[StorageProviders.DUMMY, StorageProviders.FILE]) 

16 def patch_various_providers( 

17 self: "TestFileAndDummyBasedDicts", 

18 monkeypatch: typing.Any, 

19 request: typing.Any, 

20 ) -> typing.Any: 

21 with monkeypatch.context() as patcher: 

22 yield patcher.setattr( 

23 SETTINGS, 

24 "dictionaries_storage_provider", 

25 request.param, 

26 ) 

27 

28 @pytest.mark.repeat(3) 

29 def test_add_to_dict( 

30 self: "TestFileAndDummyBasedDicts", 

31 app_client: typing.Any, 

32 faker_obj: typing.Any, 

33 patch_various_providers: typing.Any, # noqa: ARG002 

34 ) -> None: 

35 fake_user_name: typing.Final = faker_obj.user_name() 

36 fake_exc_word: typing.Final = faker_obj.word() 

37 path_to_dict_file: typing.Final = SETTINGS.dictionaries_path.joinpath( # pylint: disable=no-member 

38 fake_user_name, 

39 ) 

40 server_response = app_client.post( 

41 DICT_ENDPOINT, 

42 json=models.UserDictionaryRequestWithWord( 

43 user_name=fake_user_name, 

44 exception_word=fake_exc_word, 

45 ).model_dump(), 

46 ) 

47 assert server_response.status_code == 201 

48 if SETTINGS.dictionaries_storage_provider == StorageProviders.FILE: 

49 assert fake_exc_word in path_to_dict_file.read_text() 

50 

51 @pytest.mark.repeat(3) 

52 def test_remove_from_user_dict( 

53 self: "TestFileAndDummyBasedDicts", 

54 app_client: typing.Any, 

55 faker_obj: typing.Any, 

56 patch_various_providers: typing.Any, # noqa: ARG002 

57 ) -> None: 

58 fake_exc_word: typing.Final = faker_obj.word() 

59 fake_user_name: typing.Final = faker_obj.user_name() 

60 path_to_dict_file: typing.Final = SETTINGS.dictionaries_path.joinpath( # pylint: disable=no-member 

61 fake_user_name, 

62 ) 

63 path_to_dict_file.touch() 

64 path_to_dict_file.write_text(fake_exc_word) 

65 if SETTINGS.dictionaries_storage_provider == StorageProviders.FILE: 

66 assert fake_exc_word in path_to_dict_file.read_text() 

67 server_response = app_client.request( 

68 "DELETE", 

69 DICT_ENDPOINT, 

70 json=models.UserDictionaryRequestWithWord( 

71 user_name=fake_user_name, 

72 exception_word=fake_exc_word, 

73 ).model_dump(), 

74 ) 

75 assert server_response.status_code == 200 

76 if SETTINGS.dictionaries_storage_provider == StorageProviders.FILE: 

77 assert fake_exc_word not in path_to_dict_file.read_text() 

78 

79 def test_dummy_provider_init( 

80 self: "TestFileAndDummyBasedDicts", 

81 monkeypatch: typing.Any, 

82 app_client: typing.Any, 

83 faker_obj: typing.Any, 

84 ) -> None: 

85 monkeypatch.setattr( 

86 SETTINGS, 

87 "dictionaries_storage_provider", 

88 StorageProviders.DUMMY, 

89 ) 

90 server_response = app_client.post( 

91 DICT_ENDPOINT, 

92 json=models.UserDictionaryRequestWithWord( 

93 user_name=faker_obj.user_name(), 

94 exception_word=faker_obj.word(), 

95 ).model_dump(), 

96 ) 

97 assert server_response.status_code == 201 

98 

99 

100class TestVarious: 

101 def test_disabled_dictionary_views( 

102 self: "TestVarious", 

103 monkeypatch: typing.Any, 

104 ) -> None: 

105 """Test views with dictionaries_disabled SETTINGS option.""" 

106 with monkeypatch.context() as patcher: 

107 patcher.setattr(SETTINGS, "dictionaries_disabled", True) 

108 importlib.reload(views) 

109 server_response = TestClient(views.SPELL_APP).post( 

110 DICT_ENDPOINT, 

111 json=models.UserDictionaryRequestWithWord( 

112 user_name="test", 

113 exception_word="test", 

114 ).model_dump(), 

115 ) 

116 assert server_response.status_code == 404 

117 # restore back api state to ensure other tests wont break 

118 importlib.reload(views) 

119 

120 @pytest.mark.parametrize("api_key", [None, ""]) 

121 def test_empty_auth_key(self: "TestVarious", api_key: str) -> None: 

122 server_response = TestClient(views.SPELL_APP).post( 

123 DICT_ENDPOINT, 

124 json=models.UserDictionaryRequestWithWord( 

125 user_name="test", 

126 exception_word="test", 

127 ).model_dump(), 

128 headers={} if api_key is None else {SETTINGS.api_key_header_name: ""}, 

129 ) 

130 assert server_response.status_code == 403 

131 

132 def test_wrong_api_key(self: "TestVarious") -> None: 

133 server_response = TestClient(views.SPELL_APP).post( 

134 DICT_ENDPOINT, 

135 json=models.UserDictionaryRequestWithWord( 

136 user_name="test", 

137 exception_word="test", 

138 ).model_dump(), 

139 headers={ 

140 SETTINGS.api_key_header_name: SETTINGS.api_key + "wrongTrashKekJunk --- 5000", 

141 }, 

142 ) 

143 assert server_response.status_code == 401