Skip to content

Commit 1666feb

Browse files
committed
refs #278 First bits of unit testing set up
Going to try to keep related items in each file. We will probably need a dataset_test.py, form_test.py, etc...
1 parent 3527c37 commit 1666feb

File tree

4 files changed

+295
-1
lines changed

4 files changed

+295
-1
lines changed

pysimplesql/pysimplesql.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -7413,7 +7413,7 @@ class Sqlserver(SQLDriver):
74137413
def __init__(
74147414
self, host, user, password, database, sql_script=None, sql_commands=None
74157415
):
7416-
super().__init__(name="Sqlserver", table_quote='"', placeholder="?")
7416+
super().__init__(name="Sqlserver", table_quote="[]", placeholder="?")
74177417

74187418
self.name = "Sqlserver"
74197419
self.host = host

tests/sqldriver_test.py

+262
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
# ruff: skip-file
2+
3+
import contextlib
4+
5+
import docker.errors
6+
import pytest
7+
8+
import pysimplesql as ss
9+
from pysimplesql.docker_utils import * # noqa F403
10+
11+
12+
# --------------------------------------------------------------------------------------
13+
# Create session-level fixtures for the docker containers to provide database servers
14+
# --------------------------------------------------------------------------------------
15+
@pytest.fixture(scope="session", autouse=True)
16+
def mysql_container():
17+
docker_image = "pysimplesql/examples:mysql"
18+
docker_image_pull(docker_image)
19+
docker_container = docker_container_start(
20+
image=docker_image,
21+
container_name="pysimplesql-examples-mysql",
22+
ports={"3306/tcp": ("127.0.0.1", 3306)},
23+
)
24+
yield docker_container
25+
with contextlib.suppress(docker.errors.APIError):
26+
docker_container.stop()
27+
28+
29+
@pytest.fixture(scope="session", autouse=True)
30+
def postgres_container():
31+
docker_image = "pysimplesql/examples:postgres"
32+
docker_image_pull(docker_image)
33+
docker_container = docker_container_start(
34+
image=docker_image,
35+
container_name="pysimplesql-examples-postgres",
36+
ports={"5432/tcp": ("127.0.0.1", 5432)},
37+
)
38+
yield docker_container
39+
with contextlib.suppress(docker.errors.APIError):
40+
docker_container.stop()
41+
42+
43+
@pytest.fixture(scope="session", autouse=True)
44+
def sqlserver_container():
45+
docker_image = "pysimplesql/examples:sqlserver"
46+
docker_image_pull(docker_image)
47+
docker_container = docker_container_start(
48+
image=docker_image,
49+
container_name="pysimplesql-examples-sqlserver",
50+
ports={"1433/tcp": ("127.0.0.1", 1433)},
51+
)
52+
yield docker_container
53+
with contextlib.suppress(docker.errors.APIError):
54+
docker_container.stop()
55+
56+
57+
# Credentials to use each with the docker servers
58+
mysql_docker = {
59+
"user": "pysimplesql_user",
60+
"password": "pysimplesql",
61+
"host": "127.0.0.1",
62+
"database": "pysimplesql_examples",
63+
}
64+
65+
postgres_docker = {
66+
"host": "localhost",
67+
"user": "pysimplesql_user",
68+
"password": "pysimplesql",
69+
"database": "pysimplesql_examples",
70+
}
71+
72+
sqlserver_docker = {
73+
"host": "127.0.0.1",
74+
"user": "pysimplesql_user",
75+
"password": "Pysimplesql!",
76+
"database": "pysimplesql_examples",
77+
}
78+
79+
80+
# --------------------------------------------------------------------------------------
81+
# Use a fixture to create a driver instance for each test
82+
# --------------------------------------------------------------------------------------
83+
@pytest.fixture(
84+
params=[
85+
ss.Driver.sqlite,
86+
ss.Driver.flatfile,
87+
ss.Driver.mysql,
88+
ss.Driver.postgres,
89+
ss.Driver.sqlserver,
90+
ss.Driver.msaccess,
91+
]
92+
)
93+
def driver(request):
94+
driver_class = request.param
95+
96+
if driver_class == ss.Driver.sqlite:
97+
return driver_class(
98+
db_path=":memory:"
99+
) # Use an in-memory database for sqlite tests
100+
elif driver_class == ss.Driver.flatfile:
101+
return driver_class(file_path="test.csv")
102+
elif driver_class == ss.Driver.mysql:
103+
return driver_class(**mysql_docker)
104+
elif driver_class == ss.Driver.postgres:
105+
return driver_class(**postgres_docker)
106+
elif driver_class == ss.Driver.sqlserver:
107+
return driver_class(**sqlserver_docker)
108+
elif driver_class == ss.Driver.msaccess:
109+
return driver_class(database_file="test.accdb")
110+
else:
111+
raise NotImplementedError("Driver class not supported in tests.")
112+
113+
114+
# --------------------------------------------------------------------------------------
115+
# General tests that apply to all SQLDriver implementations
116+
# --------------------------------------------------------------------------------------
117+
# Note: driver-specific implementations will be provided after this section
118+
119+
120+
# Test creating a connection
121+
@pytest.mark.parametrize(
122+
"driver",
123+
[
124+
ss.Driver.sqlite,
125+
ss.Driver.flatfile,
126+
ss.Driver.mysql,
127+
ss.Driver.postgres,
128+
ss.Driver.sqlserver,
129+
ss.Driver.msaccess,
130+
],
131+
indirect=True,
132+
)
133+
def test_connect(driver):
134+
driver_class = driver.__class__
135+
136+
# Note: We don't actually need to look at the driver classes in this case
137+
# as the action for all is exactly the same. I just wanted a good example
138+
# of how we can separate logic out for individual drivers if needed.
139+
if driver_class == ss.Driver.sqlite:
140+
assert driver.con is not None
141+
elif driver_class == ss.Driver.flatfile:
142+
assert driver.con is not None # uses sqlite, so should have con
143+
elif driver_class == ss.Driver.mysql:
144+
assert driver.con is not None
145+
elif driver_class == ss.Driver.postgres:
146+
assert driver.con is not None
147+
elif driver_class == ss.Driver.sqlserver:
148+
assert driver.con is not None
149+
elif driver_class == ss.Driver.msaccess:
150+
assert driver.con is not None
151+
else:
152+
raise NotImplementedError("Driver class not supported in tests.")
153+
154+
155+
# Test closing a connection
156+
@pytest.mark.parametrize(
157+
"driver",
158+
[
159+
ss.Driver.sqlite,
160+
ss.Driver.flatfile,
161+
ss.Driver.mysql,
162+
ss.Driver.postgres,
163+
ss.Driver.sqlserver,
164+
ss.Driver.msaccess,
165+
],
166+
indirect=True,
167+
)
168+
def test_close(driver):
169+
# Close the driver
170+
driver.close()
171+
172+
# Now see if we can execute a simple query. If we can, it did not close properly
173+
query = "SELECT 1"
174+
175+
with pytest.raises(Exception):
176+
driver.execute(query)
177+
178+
179+
# Test creating tables
180+
@pytest.mark.parametrize(
181+
"driver",
182+
[
183+
ss.Driver.sqlite,
184+
ss.Driver.flatfile,
185+
ss.Driver.mysql,
186+
ss.Driver.postgres,
187+
ss.Driver.sqlserver,
188+
# ss.Driver.msaccess, #MSAccess not quite working yet...
189+
],
190+
indirect=True,
191+
)
192+
def test_create_table(driver: ss.SQLDriver):
193+
driver_class = driver.__class__
194+
# Create
195+
table = "TestAaBb123"
196+
table_quoted = driver.quote_table(table)
197+
198+
# Drop the table so we start clean
199+
query = f"DROP TABLE IF EXISTS {table_quoted};"
200+
driver.execute(query)
201+
driver.commit()
202+
203+
reference_tables = driver.get_tables()
204+
print(driver_class, "reference_tables", reference_tables)
205+
assert table not in reference_tables
206+
207+
# Now create the table
208+
query = f"CREATE TABLE {table_quoted} (id INTEGER);"
209+
driver.execute(query)
210+
driver.commit()
211+
212+
# Get tables again
213+
tables = driver.get_tables()
214+
print(driver_class, "tables", tables)
215+
assert table in tables
216+
217+
218+
"""
219+
@pytest.mark.parametrize("sql_driver_instance", [
220+
ss.Driver.sqlite,
221+
ss.Driver.flatfile,
222+
ss.Driver.mysql,
223+
ss.Driver.postgres,
224+
ss.Driver.sqlserver,
225+
ss.Driver.msaccess
226+
], indirect=True)
227+
def test_get_tables(sql_driver_instance):
228+
229+
230+
@pytest.mark.parametrize("sql_driver_instance", [
231+
ss.Driver.sqlite,
232+
ss.Driver.flatfile,
233+
ss.Driver.mysql,
234+
ss.Driver.postgres,
235+
ss.Driver.sqlserver,
236+
ss.Driver.msaccess
237+
], indirect=True)
238+
def test_column_info(sql_driver_instance):
239+
240+
241+
@pytest.mark.parametrize("sql_driver_instance", [
242+
ss.Driver.sqlite,
243+
ss.Driver.flatfile,
244+
ss.Driver.mysql,
245+
ss.Driver.postgres,
246+
ss.Driver.sqlserver,
247+
ss.Driver.msaccess
248+
], indirect=True)
249+
def test_execute_query(sql_driver_instance):
250+
251+
252+
@pytest.mark.parametrize("sql_driver_instance", [
253+
ss.Driver.sqlite,
254+
ss.Driver.flatfile,
255+
ss.Driver.mysql,
256+
ss.Driver.postgres,
257+
ss.Driver.sqlserver,
258+
ss.Driver.msaccess
259+
], indirect=True)
260+
def test_relationships(sql_driver_instance):
261+
262+
"""

tests/test.accdb

660 KB
Binary file not shown.

tests/test.csv

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# ----------------------------------------------------------------------------------------------------------------------
2+
# CSV FILE EXAMPLE FOR PYSIMPLESQL FLATFILE DRIVER
3+
# ----------------------------------------------------------------------------------------------------------------------
4+
# While most CSV files start at line 0, some reserve an area for general use. This is just to show that the Flatfile
5+
# driver can handle special cases like this.
6+
#
7+
# Note that the header data starts on row 10 (counting from 0), so we will have to use the header_row_num parameter to
8+
# load this file properly!
9+
# Aso note the comment symbols here mean absolutely nothing, all lines before the header_row_num are just skipped
10+
# ----------------------------------------------------------------------------------------------------------------------
11+
name,address,phone,email
12+
Aaron Leeds,888 Palm Ave. Palmtown CA 90210,310-555-1212,[email protected]
13+
Adam Lee,888 Pineapple Dr. Pineappleville HI 96801,808-555-1212,[email protected]
14+
Amy Patel,101 Rosewood Ave. Rosetown MN 55112,651-555-1212,[email protected]
15+
Anthony Brown,789 Pine St. Pinetown TN 37013,615-555-1212,[email protected]
16+
Chris Campbell,123 Maple St. Mapletown IN 46321,219-555-1212,[email protected]
17+
David Brown,246 Pine St. Greenvale NY 11548,516-555-1212,[email protected]
18+
Emily Davis,222 Cypress Rd. Bayview FL 33009,954-555-1212,[email protected]
19+
Ethan Wilson,753 Oak Rd. Oakville VT 05657,802-555-1212,[email protected]
20+
Jack Green,753 Walnut St. Rivertown OH 44116,440-555-1212,[email protected]
21+
Jane Doe,456 Elm St. Anytown NC 27549,919-555-1212,[email protected]
22+
Jennifer Taylor,456 Lemon St. Lemonville TX 75006,469-555-1212,[email protected]
23+
Jessica Nguyen,101 Birch Ln. Birchville NV 89703,775-555-1212,[email protected]
24+
John Smith,123 Main St. Smalltown OH 44082,440-555-1212, [email protected]
25+
Lisa Williams,101 Maple Ave. Hickory NC 28601,828-555-1212,[email protected]
26+
Madison Garcia,222 Willow St. Willowdale WA 98020,425-555-1212,[email protected]
27+
Matthew Chen,555 Peachtree Rd. Peachtree City GA 30269,770-555-1212,[email protected]
28+
Mike Johnson,789 Oak St. Largetown IL 60142,815-555-1212,[email protected]
29+
Olivia Davis,369 Cedar St. Cedartown MA 02139,617-555-1212,[email protected]
30+
Rachel Rodriguez,456 Oak St. Oakdale AZ 85239,520-555-1212,[email protected]
31+
Sarah Lee,369 Cherry Ln. Sunnyville CA 90210,310-555-1212,[email protected]
32+
Thomas Johnson,246 Maple Rd. Mapleville RI 02839,401-555-1212,[email protected]

0 commit comments

Comments
 (0)