/ dev / clint / tests / rules / test_nested_mock_patch.py
test_nested_mock_patch.py
  1  from pathlib import Path
  2  
  3  from clint.config import Config
  4  from clint.index import SymbolIndex
  5  from clint.linter import Position, Range, lint_file
  6  from clint.rules.nested_mock_patch import NestedMockPatch
  7  
  8  
  9  def test_nested_mock_patch_unittest_mock(index: SymbolIndex) -> None:
 10      code = """
 11  import unittest.mock
 12  
 13  def test_foo():
 14      with unittest.mock.patch("foo.bar"):
 15          with unittest.mock.patch("foo.baz"):
 16              ...
 17  """
 18      config = Config(select={NestedMockPatch.name})
 19      violations = lint_file(Path("test_nested_mock_patch.py"), code, config, index)
 20      assert len(violations) == 1
 21      assert all(isinstance(v.rule, NestedMockPatch) for v in violations)
 22      assert violations[0].range == Range(Position(4, 4))
 23  
 24  
 25  def test_nested_mock_patch_from_unittest_import_mock(index: SymbolIndex) -> None:
 26      code = """
 27  from unittest import mock
 28  
 29  def test_foo():
 30      with mock.patch("foo.bar"):
 31          with mock.patch("foo.baz"):
 32              ...
 33  """
 34      config = Config(select={NestedMockPatch.name})
 35      violations = lint_file(Path("test_nested_mock_patch.py"), code, config, index)
 36      assert len(violations) == 1
 37      assert all(isinstance(v.rule, NestedMockPatch) for v in violations)
 38      assert violations[0].range == Range(Position(4, 4))
 39  
 40  
 41  def test_nested_mock_patch_object(index: SymbolIndex) -> None:
 42      code = """
 43  from unittest import mock
 44  
 45  def test_foo():
 46      with mock.patch.object(SomeClass, "method"):
 47          with mock.patch.object(AnotherClass, "method"):
 48              ...
 49  """
 50      config = Config(select={NestedMockPatch.name})
 51      violations = lint_file(Path("test_nested_mock_patch.py"), code, config, index)
 52      assert len(violations) == 1
 53      assert all(isinstance(v.rule, NestedMockPatch) for v in violations)
 54      assert violations[0].range == Range(Position(4, 4))
 55  
 56  
 57  def test_nested_mock_patch_dict(index: SymbolIndex) -> None:
 58      code = """
 59  from unittest import mock
 60  
 61  def test_foo():
 62      with mock.patch.dict("os.environ", {"FOO": "bar"}):
 63          with mock.patch.dict("os.environ", {"BAZ": "qux"}):
 64              ...
 65  """
 66      config = Config(select={NestedMockPatch.name})
 67      violations = lint_file(Path("test_nested_mock_patch.py"), code, config, index)
 68      assert len(violations) == 1
 69      assert all(isinstance(v.rule, NestedMockPatch) for v in violations)
 70      assert violations[0].range == Range(Position(4, 4))
 71  
 72  
 73  def test_nested_mock_patch_mixed(index: SymbolIndex) -> None:
 74      code = """
 75  from unittest import mock
 76  
 77  def test_foo():
 78      with mock.patch("foo.bar"):
 79          with mock.patch.object(SomeClass, "method"):
 80              ...
 81  """
 82      config = Config(select={NestedMockPatch.name})
 83      violations = lint_file(Path("test_nested_mock_patch.py"), code, config, index)
 84      assert len(violations) == 1
 85      assert all(isinstance(v.rule, NestedMockPatch) for v in violations)
 86      assert violations[0].range == Range(Position(4, 4))
 87  
 88  
 89  def test_multiple_context_managers_is_ok(index: SymbolIndex) -> None:
 90      code = """
 91  from unittest import mock
 92  
 93  def test_foo():
 94      with mock.patch("foo.bar"), mock.patch("foo.baz"):
 95          ...
 96  """
 97      config = Config(select={NestedMockPatch.name})
 98      violations = lint_file(Path("test_nested_mock_patch.py"), code, config, index)
 99      assert len(violations) == 0
100  
101  
102  def test_multiple_context_managers_with_object_is_ok(index: SymbolIndex) -> None:
103      code = """
104  from unittest import mock
105  
106  def test_foo():
107      with mock.patch("foo.bar"), mock.patch.object(SomeClass, "method"):
108          ...
109  """
110      config = Config(select={NestedMockPatch.name})
111      violations = lint_file(Path("test_nested_mock_patch.py"), code, config, index)
112      assert len(violations) == 0
113  
114  
115  def test_nested_with_but_not_mock_patch_is_ok(index: SymbolIndex) -> None:
116      code = """
117  def test_foo():
118      with open("file.txt"):
119          with open("file2.txt"):
120              ...
121  """
122      config = Config(select={NestedMockPatch.name})
123      violations = lint_file(Path("test_nested_mock_patch.py"), code, config, index)
124      assert len(violations) == 0
125  
126  
127  def test_nested_with_only_one_mock_patch_is_ok(index: SymbolIndex) -> None:
128      code = """
129  from unittest import mock
130  
131  def test_foo():
132      with mock.patch("foo.bar"):
133          with open("file.txt"):
134              ...
135  """
136      config = Config(select={NestedMockPatch.name})
137      violations = lint_file(Path("test_nested_mock_patch.py"), code, config, index)
138      assert len(violations) == 0
139  
140  
141  def test_non_nested_mock_patches_are_ok(index: SymbolIndex) -> None:
142      code = """
143  from unittest import mock
144  
145  def test_foo():
146      with mock.patch("foo.bar"):
147          pass
148      with mock.patch("foo.baz"):
149          pass
150  """
151      config = Config(select={NestedMockPatch.name})
152      violations = lint_file(Path("test_nested_mock_patch.py"), code, config, index)
153      assert len(violations) == 0
154  
155  
156  def test_non_test_file_not_checked(index: SymbolIndex) -> None:
157      code = """
158  from unittest import mock
159  
160  def foo():
161      with mock.patch("foo.bar"):
162          with mock.patch("foo.baz"):
163              ...
164  """
165      config = Config(select={NestedMockPatch.name})
166      violations = lint_file(Path("nested_mock_patch.py"), code, config, index)
167      assert len(violations) == 0
168  
169  
170  def test_nested_with_code_after_is_ok(index: SymbolIndex) -> None:
171      code = """
172  from unittest import mock
173  
174  def test_foo():
175      with mock.patch("foo.bar"):
176          with mock.patch("foo.baz"):
177              ...
178  
179          assert True
180  """
181      config = Config(select={NestedMockPatch.name})
182      violations = lint_file(Path("test_nested_mock_patch.py"), code, config, index)
183      assert len(violations) == 0
184  
185  
186  def test_deeply_nested_mock_patch(index: SymbolIndex) -> None:
187      code = """
188  from unittest import mock
189  
190  def test_foo():
191      with mock.patch("foo.bar"):
192          with mock.patch("foo.baz"):
193              with mock.patch("foo.qux"):
194                  ...
195  """
196      config = Config(select={NestedMockPatch.name})
197      violations = lint_file(Path("test_nested_mock_patch.py"), code, config, index)
198      # Should detect both levels of nesting
199      assert len(violations) == 2
200      assert all(isinstance(v.rule, NestedMockPatch) for v in violations)
201      assert violations[0].range == Range(Position(4, 4))
202      assert violations[1].range == Range(Position(5, 8))