Skip to content
This repository was archived by the owner on Mar 20, 2026. It is now read-only.

Commit 2bb3fff

Browse files
committed
feat: added unit test coverage for functions, introspection and schema
1 parent 8b69cc8 commit 2bb3fff

5 files changed

Lines changed: 617 additions & 151 deletions

File tree

django_spanner/schema.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,6 @@ def create_model(self, model):
4848
:param model: A model for creating a table.
4949
"""
5050
# Create column SQL, add FK deferreds if needed
51-
import pdb
52-
53-
pdb.set_trace()
5451
column_sqls = []
5552
params = []
5653
for field in model._meta.local_fields:
@@ -94,9 +91,6 @@ def create_model(self, model):
9491
self.deferred_sql.append(
9592
self._create_unique_sql(model, [field.column])
9693
)
97-
import pdb
98-
99-
pdb.set_trace()
10094
# Add any unique_togethers (always deferred, as some fields might be
10195
# created afterwards, like geometry fields with some backends)
10296
for fields in model._meta.unique_together:

tests/settings.py

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,9 @@
1919

2020
ENGINE = "django_spanner"
2121
PROJECT = os.getenv(
22-
"GOOGLE_CLOUD_PROJECT",
23-
os.getenv("PROJECT_ID", "emulator-test-project"),
22+
"GOOGLE_CLOUD_PROJECT", os.getenv("PROJECT_ID", "emulator-test-project"),
2423
)
2524

26-
# "PROJECT": "precise-truck-742",
27-
# "INSTANCE": "libc-django-test",
28-
# "us-west1"
29-
30-
INSTANCE_CONFIG = f"{PROJECT}/instanceConfigs/regional-us-central1"
3125
INSTANCE = "django-test-instance"
3226
NAME = "spanner-django-test-{}".format(str(int(time.time())))
3327

@@ -44,10 +38,3 @@
4438
PASSWORD_HASHERS = [
4539
"django.contrib.auth.hashers.MD5PasswordHasher",
4640
]
47-
48-
SITE_ID = 1
49-
50-
CONN_MAX_AGE = 60
51-
52-
OPTIONS = {}
53-
AUTOCOMMIT = False
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
# Copyright 2020 Google LLC
2+
#
3+
# Use of this source code is governed by a BSD-style
4+
# license that can be found in the LICENSE file or at
5+
# https://developers.google.com/open-source/licenses/bsd
6+
7+
import sys
8+
import unittest
9+
10+
from django.test import SimpleTestCase
11+
from django_spanner.compiler import SQLCompiler
12+
from django.db.models import CharField, FloatField, Value
13+
from django.db.models.functions import (
14+
Cast,
15+
Concat,
16+
Cot,
17+
Degrees,
18+
Log,
19+
Ord,
20+
Pi,
21+
Radians,
22+
StrIndex,
23+
Substr,
24+
Left,
25+
Right,
26+
)
27+
from .models import Author
28+
29+
30+
@unittest.skipIf(
31+
sys.version_info < (3, 6), reason="Skipping Python versions <= 3.5"
32+
)
33+
class TestUtils(SimpleTestCase):
34+
def _get_target_class(self):
35+
from django_spanner.base import DatabaseWrapper
36+
37+
return DatabaseWrapper
38+
39+
def _make_one(self, *args, **kwargs):
40+
"""
41+
Returns a connection to the database provided in settings.
42+
"""
43+
dummy_settings = {"dummy_param": "dummy"}
44+
return self._get_target_class()(settings_dict=dummy_settings)
45+
46+
# Tests
47+
def test_cast_with_max_length(self):
48+
"""
49+
Tests cast field with max length.
50+
"""
51+
connection = self._make_one()
52+
q1 = Author.objects.values("name").annotate(
53+
name_as_prefix=Cast("name", output_field=CharField(max_length=10)),
54+
)
55+
compiler = SQLCompiler(q1.query, connection, "default")
56+
sql_query, params = compiler.query.as_sql(compiler, connection)
57+
self.assertEqual(
58+
sql_query,
59+
"SELECT tests_author.name, SUBSTR(CAST(tests_author.name AS "
60+
+ "STRING), 0, 10) AS name_as_prefix FROM tests_author",
61+
)
62+
self.assertEqual(params, ())
63+
64+
def test_cast_without_max_length(self):
65+
"""
66+
Tests cast field without max length.
67+
"""
68+
connection = self._make_one()
69+
q1 = Author.objects.values("num").annotate(
70+
num_as_float=Cast("num", output_field=FloatField()),
71+
)
72+
compiler = SQLCompiler(q1.query, connection, "default")
73+
sql_query, params = compiler.query.as_sql(compiler, connection)
74+
self.assertEqual(
75+
sql_query,
76+
"SELECT tests_author.num, CAST(tests_author.num AS FLOAT64) "
77+
+ "AS num_as_float FROM tests_author",
78+
)
79+
self.assertEqual(params, ())
80+
81+
def test_concatpair(self):
82+
"""
83+
Tests concat pair.
84+
"""
85+
connection = self._make_one()
86+
q1 = Author.objects.values("name").annotate(
87+
full_name=Concat(
88+
"name", Value(" "), "last_name", output_field=CharField()
89+
),
90+
)
91+
compiler = SQLCompiler(q1.query, connection, "default")
92+
sql_query, params = compiler.query.as_sql(compiler, connection)
93+
self.assertEqual(
94+
sql_query,
95+
"SELECT tests_author.name, CONCAT(IFNULL(tests_author.name, %s), "
96+
+ "IFNULL(CONCAT(IFNULL(%s, %s), IFNULL(tests_author.last_name, "
97+
+ "%s)), %s)) AS full_name FROM tests_author",
98+
)
99+
self.assertEqual(params, ("", " ", "", "", ""))
100+
101+
def test_cot(self):
102+
"""
103+
Tests cot function.
104+
"""
105+
connection = self._make_one()
106+
q1 = Author.objects.values("num").annotate(num_cot=Cot("num"),)
107+
compiler = SQLCompiler(q1.query, connection, "default")
108+
sql_query, params = compiler.query.as_sql(compiler, connection)
109+
self.assertEqual(
110+
sql_query,
111+
"SELECT tests_author.num, (1 / TAN(tests_author.num)) AS num_cot "
112+
+ "FROM tests_author",
113+
)
114+
self.assertEqual(params, ())
115+
116+
def test_degrees(self):
117+
"""
118+
Tests degrees function.
119+
"""
120+
connection = self._make_one()
121+
q1 = Author.objects.values("num").annotate(num_degrees=Degrees("num"),)
122+
compiler = SQLCompiler(q1.query, connection, "default")
123+
sql_query, params = compiler.query.as_sql(compiler, connection)
124+
self.assertEqual(
125+
sql_query,
126+
"SELECT tests_author.num, ((tests_author.num) * 180 / "
127+
+ "3.141592653589793) AS num_degrees FROM tests_author",
128+
)
129+
self.assertEqual(params, ())
130+
131+
def test_left(self):
132+
"""
133+
Tests degrees function.
134+
"""
135+
connection = self._make_one()
136+
q1 = Author.objects.values("num").annotate(
137+
first_initial=Left("name", 1),
138+
)
139+
compiler = SQLCompiler(q1.query, connection, "default")
140+
sql_query, params = compiler.query.as_sql(compiler, connection)
141+
self.assertEqual(
142+
sql_query,
143+
"SELECT tests_author.num, SUBSTR(tests_author.name, %s, %s) AS "
144+
+ "first_initial FROM tests_author",
145+
)
146+
self.assertEqual(params, (1, 1))
147+
148+
def test_right(self):
149+
"""
150+
Tests degrees function.
151+
"""
152+
connection = self._make_one()
153+
q1 = Author.objects.values("num").annotate(
154+
last_letter=Right("name", 1),
155+
)
156+
compiler = SQLCompiler(q1.query, connection, "default")
157+
sql_query, params = compiler.query.as_sql(compiler, connection)
158+
self.assertEqual(
159+
sql_query,
160+
"SELECT tests_author.num, SUBSTR(tests_author.name, (%s * %s)) "
161+
+ "AS last_letter FROM tests_author",
162+
)
163+
self.assertEqual(params, (1, -1))
164+
165+
def test_log(self):
166+
"""
167+
Tests log function.
168+
"""
169+
connection = self._make_one()
170+
q1 = Author.objects.values("num").annotate(log=Log("num", Value(10)))
171+
172+
compiler = SQLCompiler(q1.query, connection, "default")
173+
sql_query, params = compiler.query.as_sql(compiler, connection)
174+
self.assertEqual(
175+
sql_query,
176+
"SELECT tests_author.num, LOG(%s, tests_author.num) AS log FROM "
177+
+ "tests_author",
178+
)
179+
self.assertEqual(params, (10,))
180+
181+
def test_ord(self):
182+
"""
183+
Tests ord function.
184+
"""
185+
connection = self._make_one()
186+
q1 = Author.objects.values("name").annotate(
187+
name_code_point=Ord("name")
188+
)
189+
190+
compiler = SQLCompiler(q1.query, connection, "default")
191+
sql_query, params = compiler.query.as_sql(compiler, connection)
192+
self.assertEqual(
193+
sql_query,
194+
"SELECT tests_author.name, TO_CODE_POINTS(tests_author.name)"
195+
+ "[OFFSET(0)] AS name_code_point FROM tests_author",
196+
)
197+
self.assertEqual(params, ())
198+
199+
def test_pi(self):
200+
"""
201+
Tests pi function.
202+
"""
203+
connection = self._make_one()
204+
q1 = Author.objects.filter(num=Pi()).values("num")
205+
206+
compiler = SQLCompiler(q1.query, connection, "default")
207+
sql_query, params = compiler.query.as_sql(compiler, connection)
208+
self.assertEqual(
209+
sql_query,
210+
"SELECT tests_author.num FROM tests_author WHERE tests_author.num "
211+
+ "= (3.141592653589793)",
212+
)
213+
self.assertEqual(params, ())
214+
215+
def test_radians(self):
216+
"""
217+
Tests radians function.
218+
"""
219+
connection = self._make_one()
220+
q1 = Author.objects.values("num").annotate(num_radians=Radians("num"))
221+
222+
compiler = SQLCompiler(q1.query, connection, "default")
223+
sql_query, params = compiler.query.as_sql(compiler, connection)
224+
self.assertEqual(
225+
sql_query,
226+
"SELECT tests_author.num, ((tests_author.num) * 3.141592653589793 "
227+
"/ 180) AS num_radians FROM tests_author",
228+
)
229+
self.assertEqual(params, ())
230+
231+
def test_strindex(self):
232+
"""
233+
Tests str index query.
234+
"""
235+
connection = self._make_one()
236+
q1 = Author.objects.values("name").annotate(
237+
smith_index=StrIndex("name", Value("Smith"))
238+
)
239+
240+
compiler = SQLCompiler(q1.query, connection, "default")
241+
sql_query, params = compiler.query.as_sql(compiler, connection)
242+
self.assertEqual(
243+
sql_query,
244+
"SELECT tests_author.name, STRPOS(tests_author.name, %s) AS "
245+
+ "smith_index FROM tests_author",
246+
)
247+
self.assertEqual(params, ("Smith",))
248+
249+
def test_substr(self):
250+
"""
251+
Tests substr query.
252+
"""
253+
connection = self._make_one()
254+
q1 = Author.objects.values("name").annotate(
255+
name_prefix=Substr("name", 1, 5)
256+
)
257+
258+
compiler = SQLCompiler(q1.query, connection, "default")
259+
sql_query, params = compiler.query.as_sql(compiler, connection)
260+
self.assertEqual(
261+
sql_query,
262+
"SELECT tests_author.name, SUBSTR(tests_author.name, %s, %s) AS "
263+
+ "name_prefix FROM tests_author",
264+
)
265+
self.assertEqual(params, (1, 5))

0 commit comments

Comments
 (0)