Coverage for .tox/coverage/lib/python3.11/site-packages/wuttjamaican/testing.py: 100%
53 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-12-31 19:12 -0600
« prev ^ index » next coverage.py v7.11.0, created at 2025-12-31 19:12 -0600
1# -*- coding: utf-8; -*-
2################################################################################
3#
4# WuttJamaican -- Base package for Wutta Framework
5# Copyright © 2023-2025 Lance Edgar
6#
7# This file is part of Wutta Framework.
8#
9# Wutta Framework is free software: you can redistribute it and/or modify it
10# under the terms of the GNU General Public License as published by the Free
11# Software Foundation, either version 3 of the License, or (at your option) any
12# later version.
13#
14# Wutta Framework is distributed in the hope that it will be useful, but
15# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17# more details.
18#
19# You should have received a copy of the GNU General Public License along with
20# Wutta Framework. If not, see <http://www.gnu.org/licenses/>.
21#
22################################################################################
23"""
24WuttJamaican - test utilities
25"""
27import os
28import shutil
29import tempfile
30import warnings
31from unittest import TestCase
33from wuttjamaican.conf import WuttaConfig
36class FileTestCase(TestCase):
37 """
38 Base class for test suites which (may) write temporary files, for
39 sake of testing the config constructor etc. It inherits from
40 :class:`python:unittest.TestCase`.
42 This class creates a temporary folder on setup, and removes it on
43 teardown. See below for features exposed to work with the folder.
45 .. attribute:: tempdir
47 Path to the temporary folder created during setup.
49 .. note::
51 If you subclass this and need to override setup/teardown,
52 please be sure to call the corresponding methods for this
53 class.
54 """
56 def setUp(self): # pylint: disable=empty-docstring
57 """ """
58 self.setup_files()
60 def setup_files(self):
61 """
62 This creates the temporary folder.
63 """
64 self.tempdir = tempfile.mkdtemp()
66 def setup_file_config(self): # pragma: no cover; pylint: disable=empty-docstring
67 """ """
68 warnings.warn(
69 "FileTestCase.setup_file_config() is deprecated; "
70 "please use setup_files() instead",
71 DeprecationWarning,
72 stacklevel=2,
73 )
74 self.setup_files()
76 def tearDown(self): # pylint: disable=empty-docstring
77 """ """
78 self.teardown_files()
80 def teardown_files(self):
81 """
82 This removes the temporary folder.
83 """
84 shutil.rmtree(self.tempdir)
86 def teardown_file_config(self): # pragma: no cover; pylint: disable=empty-docstring
87 """ """
88 warnings.warn(
89 "FileTestCase.teardown_file_config() is deprecated; "
90 "please use teardown_files() instead",
91 DeprecationWarning,
92 stacklevel=2,
93 )
94 self.teardown_files()
96 def write_file(self, filename, content):
97 """
98 Write a new file (in temporary folder) with the given filename
99 and content, and return its full path. For instance::
101 myconf = self.write_file('my.conf', '<file contents>')
102 """
103 path = os.path.join(self.tempdir, filename)
104 with open(path, "wt", encoding="utf_8") as f:
105 f.write(content)
106 return path
108 def mkdir(
109 self, dirname
110 ): # pragma: no cover; pylint: disable=unused-argument,empty-docstring
111 """ """
112 warnings.warn(
113 "FileTestCase.mkdir() is deprecated; "
114 "please use FileTestCase.mkdtemp() instead",
115 DeprecationWarning,
116 stacklevel=2,
117 )
118 return self.mkdtemp()
120 def mkdtemp(self):
121 """
122 Make a new temporary folder and return its path.
124 Note that this will be created *underneath* :attr:`tempdir`.
125 """
126 return tempfile.mkdtemp(dir=self.tempdir)
129# TODO: deprecate / remove this
130FileConfigTestCase = FileTestCase
133class ConfigTestCase(FileTestCase):
134 """
135 Base class for test suites requiring a config object.
137 It inherits from :class:`FileTestCase` so also has the
138 file-related methods.
140 The running test has these attributes:
142 .. attribute:: config
144 Reference to the config object.
146 .. attribute:: app
148 Reference to the app handler.
150 .. note::
152 If you subclass this directly and need to override
153 setup/teardown, please be sure to call the corresponding
154 methods for this class.
155 """
157 def setUp(self): # pylint: disable=empty-docstring
158 """ """
159 self.setup_config()
161 def setup_config(self):
162 """
163 Perform config setup operations for the test.
164 """
165 self.setup_files()
166 self.config = self.make_config()
167 self.app = self.config.get_app()
169 def tearDown(self): # pylint: disable=empty-docstring
170 """ """
171 self.teardown_config()
173 def teardown_config(self):
174 """
175 Perform config teardown operations for the test.
176 """
177 self.teardown_files()
179 def make_config( # pylint: disable=missing-function-docstring
180 self, files=None, **kwargs
181 ):
182 return WuttaConfig(files, **kwargs)
185class DataTestCase(ConfigTestCase):
186 """
187 Base class for test suites requiring a full (typical) database.
189 It inherits from :class:`FileTestCase` so also has the
190 file-related methods.
192 This uses a SQLite in-memory database and creates all tables for
193 the app model. The running test has these attributes:
195 .. attribute:: config
197 Reference to the config object.
199 .. attribute:: app
201 Reference to the app handler.
203 .. attribute:: session
205 Open session for the test DB.
207 .. note::
209 If you subclass this and need to override setup/teardown,
210 please be sure to call the corresponding methods for this
211 class.
213 However you do *not* need to call the file-related setup or
214 teardown methods, as this class handles that automatically.
215 """
217 sqlite_engine_url = "sqlite://"
219 def setUp(self): # pylint: disable=empty-docstring
220 """ """
221 self.setup_db()
223 def setup_db(self):
224 """
225 Perform config/app/db setup operations for the test.
226 """
227 self.setup_config()
229 model = self.app.model
230 model.Base.metadata.create_all(bind=self.config.appdb_engine)
231 self.session = self.app.make_session()
233 def tearDown(self): # pylint: disable=empty-docstring
234 """ """
235 self.teardown_db()
237 def teardown_db(self):
238 """
239 Perform config/app/db teardown operations for the test.
240 """
241 self.teardown_config()
243 def make_config(self, files=None, **kwargs):
244 defaults = kwargs.setdefault("defaults", {})
245 defaults.setdefault("wutta.db.default.url", self.sqlite_engine_url)
246 return super().make_config(files, **kwargs)