Skip to content

Commit ea9b286

Browse files
committed
100% test coverage 🎉
1 parent 7470030 commit ea9b286

5 files changed

Lines changed: 200 additions & 7 deletions

File tree

qbreader/asynchronous.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ class type.
190190
raise Exception(str(response.status) + " bad request")
191191

192192
json = await response.json()
193+
print(json)
193194
return QueryResponse.from_json(json)
194195

195196
async def random_tossup(

qbreader/types.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -199,20 +199,18 @@ async def check_answer_async(
199199

200200
data = {"answerline": answerline, "givenAnswer": givenAnswer}
201201

202+
temp_session: bool = False
202203
if session is None:
203-
async with aiohttp.ClientSession() as session:
204-
async with session.get(url, params=data) as response:
205-
if response.status != 200:
206-
raise Exception(str(response.status) + " bad request")
207-
208-
json = await response.json()
209-
return cls.from_json(json)
204+
temp_session = True
205+
session = aiohttp.ClientSession()
210206

211207
async with session.get(url, params=data) as response:
212208
if response.status != 200:
213209
raise Exception(str(response.status) + " bad request")
214210

215211
json = await response.json()
212+
if temp_session:
213+
await session.close()
216214
return cls.from_json(json)
217215

218216

tests/test_async.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,38 @@ async def test_check_answer(self, qb, answerline: str, givenAnswer: str):
504504
answerline=answerline, givenAnswer=givenAnswer
505505
)
506506
assert judgement.correct()
507+
judgement = await qbr.AnswerJudgement.check_answer_async(
508+
answerline=answerline, givenAnswer=givenAnswer
509+
) # testing no session provided
510+
assert judgement.correct()
511+
512+
@pytest.mark.asyncio
513+
@pytest.mark.parametrize(
514+
"answerline, givenAnswer, exception",
515+
[
516+
("Rubik's cubes [prompt on cubes and speedcubing]", 1, TypeError),
517+
(1, "Rubik's cubes", TypeError),
518+
],
519+
)
520+
async def test_check_answer_exception(
521+
self, qb, answerline: str, givenAnswer: str, exception: Exception
522+
):
523+
await async_assert_exception(
524+
qb.check_answer, exception, answerline, givenAnswer
525+
)
526+
await async_assert_exception(
527+
qbr.AnswerJudgement.check_answer_async, exception, answerline, givenAnswer
528+
)
529+
530+
@pytest.mark.asyncio
531+
async def test_check_answer_bad_response(self, qb, mock_get):
532+
mock_get(mock_status_code=404)
533+
await async_assert_exception(
534+
qb.check_answer,
535+
Exception,
536+
answerline="Rubik's cubes",
537+
givenAnswer="Rubik's cubes",
538+
)
507539

508540
@pytest.mark.asyncio
509541
async def test_close(self, qb):

tests/test_sync.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,3 +406,24 @@ def test_room_list_bad_response(self, mock_get):
406406
)
407407
def test_check_answer(self, answerline: str, givenAnswer: str):
408408
assert qb.check_answer(answerline=answerline, givenAnswer=givenAnswer).correct()
409+
410+
@pytest.mark.parametrize(
411+
"answerline, givenAnswer, exception",
412+
[
413+
("Rubik's cubes [prompt on cubes and speedcubing]", 1, TypeError),
414+
(1, "Rubik's cubes", TypeError),
415+
],
416+
)
417+
def test_check_answer_exception(
418+
self, answerline: str, givenAnswer: str, exception: Exception
419+
):
420+
assert_exception(qb.check_answer, exception, answerline, givenAnswer)
421+
422+
def test_check_answer_bad_response(self, mock_get):
423+
mock_get(mock_status_code=404)
424+
assert_exception(
425+
qb.check_answer,
426+
Exception,
427+
answerline="Rubik's cubes",
428+
givenAnswer="Rubik's cubes",
429+
)

tests/test_types.py

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
"""Test the types, classes, and structures used by the qbreader library."""
2+
3+
4+
import qbreader as qbr
5+
from qbreader.types import Bonus, Tossup
6+
7+
8+
class TestTossup:
9+
"""Test the Tossup class."""
10+
11+
tu_json = {
12+
"_id": "64a0ccb31634f2d5eb7df02a",
13+
"question": "This general class of devices could move between hypothetical castles via up and down escalators in a cycler. These devices can transfer their angular momentum to two “yo-yo” masses attached with cords in order to decrease their rotation rate. The Oberth effect describes how these devices gain kinetic energy more efficiently while at (*) periapsis. Hohmann transfers and bi-elliptic transfers are used to adjust the altitude of these devices. The trajectory-dependent delta-v budget of one of these devices can be reduced by using a slingshot maneuver. Station-keeping can help these objects remain geosynchronous. For 10 points, name this general class of devices used to collect astronomical data, such as Voyager 1.", # noqa: E501
14+
"formatted_answer": "<b><u>spacecraft</u></b> [or <b><u>spaceship</u></b>s; accept <b><u>space probe</u></b>s, <b><u>satellite</u></b>s, or <b><u>space station</u></b>s, or <b><u>space vehicle</u></b>s; prompt with <u>rocket</u>s or <u>thruster</u>s with, “To what devices are rockets attached?”] (The first clue describes the Aldrin cycle, proposed by Buzz Aldrin.)", # noqa: E501
15+
"answer": "spacecraft [or spaceships; accept space probes, satellites, or space stations, or space vehicles; prompt with rockets or thrusters with, “To what devices are rockets attached?”] (The first clue describes the Aldrin cycle, proposed by Buzz Aldrin.)", # noqa: E501
16+
"category": "Science",
17+
"subcategory": "Other Science",
18+
"packet": "64a0ccb31634f2d5eb7df01e",
19+
"set": "64a0ccb31634f2d5eb7deed5",
20+
"setName": "2023 MRNA",
21+
"setYear": 2023,
22+
"type": "tossup",
23+
"packetNumber": 9,
24+
"packetName": "09",
25+
"questionNumber": 12,
26+
"createdAt": "2023-07-02T01:02:43.628Z",
27+
"updatedAt": "2023-07-02T01:03:31.712Z",
28+
"difficulty": 7,
29+
}
30+
31+
def test_from_json(self):
32+
"""Test the from_json() classmethod."""
33+
assert Tossup.from_json(self.tu_json)
34+
35+
def test_eq(self):
36+
"""Test the __eq__ method."""
37+
tu1 = Tossup.from_json(self.tu_json)
38+
tu2 = Tossup.from_json(self.tu_json)
39+
assert tu1 == tu2
40+
assert tu1 != self.tu_json
41+
42+
def test_str(self):
43+
"""Test the __str__ method."""
44+
tu = Tossup.from_json(self.tu_json)
45+
assert str(tu) == tu.question
46+
47+
48+
class TestBonus:
49+
"""Test the Bonus class."""
50+
51+
b_json = {
52+
"_id": "644932c99f0045ff841d6792",
53+
"leadin": "Using this metal as a charge carrier avoids both cross-contamination and electrodeposition because it has four stable oxidation states: plus-two, plus-three, plus-four, and plus-five. For 10 points each:", # noqa: E501
54+
"parts": [
55+
"Name this transition metal used as the charge carrier in the most common redox flow battery for electric grids.", # noqa: E501
56+
"To balance charge between the pipes, redox flow batteries rely on one of these semipermeable barriers made of Nafion. They also separate the compartments of fuel cells.", # noqa: E501
57+
"The electrolyte of a vanadium redox flow battery is a solution of this compound. This “acid” in a lead-acid battery is prepared using a vanadium catalyst in the contact process.", # noqa: E501
58+
],
59+
"values": [],
60+
"answers": [
61+
"vanadium [or V]",
62+
"proton-exchange membranes [or PEMs; or polymer-electrolyte membranes; prompt on membranes orion-exchange membranes]", # noqa: E501
63+
"sulfuric acid [or H2SO4]",
64+
],
65+
"formatted_answers": [
66+
"<b><u>vanadium</u></b> [or <b><u>V</u></b>]",
67+
"<b><u>proton-exchange membrane</u></b>s [or <b><u>PEM</u></b>s; or polymer-<b><u>electrolyte membrane</u></b>s; prompt on <u>membrane</u>s orion-exchange <u>membrane</u>s]", # noqa: E501
68+
"<b><u>sulfuric</u></b> acid [or <b><u>H2SO4</u></b>]",
69+
],
70+
"category": "Science",
71+
"subcategory": "Chemistry",
72+
"packet": "644932c99f0045ff841d6777",
73+
"set": "644932c99f0045ff841d66fb",
74+
"setName": "2023 ACF Nationals",
75+
"setYear": 2023,
76+
"type": "bonus",
77+
"packetNumber": 4,
78+
"packetName": "Finals 2. Editors 12",
79+
"questionNumber": 7,
80+
"createdAt": "2023-04-26T14:18:49.683Z",
81+
"updatedAt": "2023-04-26T14:19:23.999Z",
82+
"difficulty": 9,
83+
}
84+
85+
def test_from_json(self):
86+
"""Test the from_json() classmethod."""
87+
assert Bonus.from_json(self.b_json)
88+
89+
def test_eq(self):
90+
"""Test the __eq__ method."""
91+
b = Bonus.from_json(self.b_json)
92+
b = Bonus.from_json(self.b_json)
93+
assert b == b
94+
assert b != self.b_json
95+
96+
def test_str(self):
97+
"""Test the __str__ method."""
98+
b = Bonus.from_json(self.b_json)
99+
assert str(b) == "\n".join(b.parts)
100+
101+
102+
class TestPacket:
103+
"""Test the Packet class."""
104+
105+
packet = qbr.Sync.packet("2023 MRNA", 5)
106+
107+
def test_eq(self):
108+
"""Test the __eq__ method."""
109+
p1 = p2 = self.packet
110+
assert p1 == p2
111+
assert p1 != "not a packet"
112+
113+
def test_str(self):
114+
"""Test the __str__ method."""
115+
assert str(self.packet)
116+
117+
def test_iter(self):
118+
"""Test the __iter__ method."""
119+
for i, (tu, b) in enumerate(self.packet):
120+
assert tu == self.packet.tossups[i]
121+
assert b == self.packet.bonuses[i]
122+
123+
124+
class TestQueryResponse:
125+
"""Test the QueryResponse class."""
126+
127+
query = qbr.Sync.query(queryString="spacecraft", maxReturnLength=1)
128+
129+
def test_str(self):
130+
"""Test the __str__ method."""
131+
assert str(self.query)
132+
133+
134+
class TestAnswerJudgement:
135+
"""Test the AnswerJudgement class."""
136+
137+
judgement = qbr.Sync.check_answer("spacecraft", "spacecraft")
138+
139+
def test_str(self):
140+
"""Test the __str__ method."""
141+
assert str(self.judgement)

0 commit comments

Comments
 (0)