tangled
alpha
login
or
join now
urschrei.eurosky.social
/
pyzotero
0
fork
atom
Pyzotero: a Python client for the Zotero API
pyzotero.readthedocs.io
zotero
0
fork
atom
overview
issues
pulls
pipelines
More tests
urschrei.eurosky.social
1 year ago
95d98789
d5b1224d
+214
-1
1 changed file
expand all
collapse all
unified
split
tests
test_zotero.py
+214
-1
tests/test_zotero.py
···
9
9
import os
10
10
import time
11
11
import unittest
12
12
-
from unittest.mock import patch
12
12
+
from unittest.mock import MagicMock, patch
13
13
14
14
import httpretty
15
15
from dateutil import parser
···
1196
1196
def tearDown(self):
1197
1197
"""Tear stuff down"""
1198
1198
HTTPretty.disable()
1199
1199
+
1200
1200
+
@httpretty.activate
1201
1201
+
def test_updated_template_comparison(self):
1202
1202
+
"""Test that ONE_HOUR is properly used for template freshness check"""
1203
1203
+
zot = z.Zotero("myuserID", "user", "myuserkey")
1204
1204
+
1205
1205
+
# Test that ONE_HOUR constant matches code expectation
1206
1206
+
self.assertEqual(z.ONE_HOUR, 3600)
1207
1207
+
1208
1208
+
# Use a simplified approach to test checking template freshness
1209
1209
+
zot.templates = {}
1210
1210
+
1211
1211
+
# Create a template
1212
1212
+
template_name = "test_template"
1213
1213
+
HTTPretty.register_uri(
1214
1214
+
HTTPretty.GET,
1215
1215
+
"https://api.zotero.org/users/myuserID/items/new",
1216
1216
+
body=json.dumps({"success": True}),
1217
1217
+
content_type="application/json",
1218
1218
+
)
1219
1219
+
1220
1220
+
# The _cache method should create a template with a timestamp
1221
1221
+
zot._cache(MagicMock(json=lambda: {"data": "test"}), template_name)
1222
1222
+
1223
1223
+
# Verify template was created with a timestamp
1224
1224
+
self.assertIn(template_name, zot.templates)
1225
1225
+
self.assertIn("updated", zot.templates[template_name])
1226
1226
+
1227
1227
+
@httpretty.activate
1228
1228
+
def test_template_cache_creation(self):
1229
1229
+
"""Test template caching in the _cache method"""
1230
1230
+
zot = z.Zotero("myuserID", "user", "myuserkey")
1231
1231
+
1232
1232
+
# Create a mock response to cache
1233
1233
+
mock_response = MagicMock()
1234
1234
+
mock_response.json.return_value = {"test": "data"}
1235
1235
+
1236
1236
+
# Call the _cache method
1237
1237
+
template_name = "test_key"
1238
1238
+
result = zot._cache(mock_response, template_name)
1239
1239
+
1240
1240
+
# Verify the template was stored correctly
1241
1241
+
self.assertIn(template_name, zot.templates)
1242
1242
+
self.assertEqual(zot.templates[template_name]["tmplt"], {"test": "data"})
1243
1243
+
self.assertIn("updated", zot.templates[template_name])
1244
1244
+
1245
1245
+
# Verify the return value is a deep copy
1246
1246
+
self.assertEqual(result, {"test": "data"})
1247
1247
+
1248
1248
+
# Modify the returned data and check it doesn't affect the cached template
1249
1249
+
result["modified"] = True
1250
1250
+
self.assertNotIn("modified", zot.templates[template_name]["tmplt"])
1251
1251
+
1252
1252
+
@httpretty.activate
1253
1253
+
def test_striplocal_local_mode(self):
1254
1254
+
"""Test _striplocal method in local mode"""
1255
1255
+
zot = z.Zotero("myuserID", "user", "myuserkey", local=True)
1256
1256
+
1257
1257
+
# Test stripping local API path
1258
1258
+
url = "http://localhost:23119/api/users/myuserID/items"
1259
1259
+
result = zot._striplocal(url)
1260
1260
+
self.assertEqual(result, "http://localhost:23119/users/myuserID/items")
1261
1261
+
1262
1262
+
# Test with more complex path
1263
1263
+
url = "http://localhost:23119/api/users/myuserID/collections/ABC123/items"
1264
1264
+
result = zot._striplocal(url)
1265
1265
+
self.assertEqual(
1266
1266
+
result, "http://localhost:23119/users/myuserID/collections/ABC123/items"
1267
1267
+
)
1268
1268
+
1269
1269
+
@httpretty.activate
1270
1270
+
def test_striplocal_remote_mode(self):
1271
1271
+
"""Test _striplocal method in remote mode (shouldn't change URL)"""
1272
1272
+
zot = z.Zotero("myuserID", "user", "myuserkey", local=False)
1273
1273
+
1274
1274
+
# Test without changing URL in remote mode
1275
1275
+
url = "https://api.zotero.org/users/myuserID/items"
1276
1276
+
result = zot._striplocal(url)
1277
1277
+
self.assertEqual(result, url)
1278
1278
+
1279
1279
+
@httpretty.activate
1280
1280
+
def test_set_fulltext(self):
1281
1281
+
"""Test set_fulltext method for setting full-text data"""
1282
1282
+
zot = z.Zotero("myuserID", "user", "myuserkey")
1283
1283
+
1284
1284
+
# Mock response from Zotero API
1285
1285
+
HTTPretty.register_uri(
1286
1286
+
HTTPretty.PUT,
1287
1287
+
"https://api.zotero.org/users/myuserID/items/ABCD1234/fulltext",
1288
1288
+
status=204,
1289
1289
+
)
1290
1290
+
1291
1291
+
# Test with PDF data
1292
1292
+
pdf_payload = {
1293
1293
+
"content": "This is the full text content",
1294
1294
+
"indexedPages": 5,
1295
1295
+
"totalPages": 10,
1296
1296
+
}
1297
1297
+
1298
1298
+
_ = zot.set_fulltext("ABCD1234", pdf_payload)
1299
1299
+
1300
1300
+
# Verify the request
1301
1301
+
request = httpretty.last_request()
1302
1302
+
self.assertEqual(request.method, "PUT")
1303
1303
+
self.assertEqual(json.loads(request.body.decode()), pdf_payload)
1304
1304
+
self.assertEqual(request.headers["Content-Type"], "application/json")
1305
1305
+
1306
1306
+
@httpretty.activate
1307
1307
+
def test_new_fulltext(self):
1308
1308
+
"""Test new_fulltext method for retrieving newer full-text content"""
1309
1309
+
zot = z.Zotero("myuserID", "user", "myuserkey")
1310
1310
+
1311
1311
+
# Mock response from Zotero API
1312
1312
+
mock_response = {
1313
1313
+
"ITEM1": {"version": 123, "indexedPages": 10, "totalPages": 10},
1314
1314
+
"ITEM2": {"version": 456, "indexedChars": 5000, "totalChars": 5000},
1315
1315
+
}
1316
1316
+
1317
1317
+
HTTPretty.register_uri(
1318
1318
+
HTTPretty.GET,
1319
1319
+
"https://api.zotero.org/users/myuserID/fulltext",
1320
1320
+
body=json.dumps(mock_response),
1321
1321
+
content_type="application/json",
1322
1322
+
)
1323
1323
+
1324
1324
+
# Set up a mock for the request attribute
1325
1325
+
zot.request = MagicMock()
1326
1326
+
zot.request.headers = {}
1327
1327
+
1328
1328
+
# Test the new_fulltext method
1329
1329
+
result = zot.new_fulltext(since=5)
1330
1330
+
1331
1331
+
# Verify the result
1332
1332
+
self.assertEqual(result, mock_response)
1333
1333
+
1334
1334
+
# Check that the correct parameters were sent
1335
1335
+
request = httpretty.last_request()
1336
1336
+
self.assertEqual(request.querystring.get("since"), ["5"])
1337
1337
+
1338
1338
+
@httpretty.activate
1339
1339
+
def test_last_modified_version(self):
1340
1340
+
"""Test the last_modified_version method"""
1341
1341
+
zot = z.Zotero("myuserID", "user", "myuserkey")
1342
1342
+
1343
1343
+
# Mock the response with a last-modified-version header
1344
1344
+
HTTPretty.register_uri(
1345
1345
+
HTTPretty.GET,
1346
1346
+
"https://api.zotero.org/users/myuserID/items",
1347
1347
+
body=self.items_doc,
1348
1348
+
content_type="application/json",
1349
1349
+
adding_headers={"last-modified-version": "1234"},
1350
1350
+
)
1351
1351
+
1352
1352
+
# Test retrieving the last modified version
1353
1353
+
version = zot.last_modified_version()
1354
1354
+
1355
1355
+
# Verify the result
1356
1356
+
self.assertEqual(version, 1234)
1357
1357
+
1358
1358
+
def test_makeiter(self):
1359
1359
+
"""Test the makeiter method that wraps iterfollow"""
1360
1360
+
zot = z.Zotero("myuserID", "user", "myuserkey")
1361
1361
+
1362
1362
+
# Create a mock method that returns items
1363
1363
+
# This is a better approach than trying to test the generator directly
1364
1364
+
mock_items = [{"key": "ITEM1"}, {"key": "ITEM2"}]
1365
1365
+
1366
1366
+
with patch.object(zot, "iterfollow") as mock_iterfollow:
1367
1367
+
# Set up the mock to return our test items
1368
1368
+
mock_iterfollow.return_value = iter([mock_items])
1369
1369
+
1370
1370
+
# Test makeiter which wraps the iterfollow generator
1371
1371
+
# Set links manually since we're not actually calling the API
1372
1372
+
zot.links = {"self": "/test", "next": "/test?start=5"}
1373
1373
+
1374
1374
+
# This should call iterfollow internally
1375
1375
+
result = zot.makeiter(lambda: None)
1376
1376
+
1377
1377
+
# Verify makeiter sets the 'next' link to the 'self' link
1378
1378
+
self.assertEqual(zot.links["next"], zot.links["self"])
1379
1379
+
1380
1380
+
# Verify makeiter returns an iterable
1381
1381
+
self.assertTrue(hasattr(result, "__iter__"))
1382
1382
+
1383
1383
+
# Verify the mock was called
1384
1384
+
mock_iterfollow.assert_called_once()
1385
1385
+
1386
1386
+
@httpretty.activate
1387
1387
+
def test_publications_user(self):
1388
1388
+
"""Test the publications method for user libraries"""
1389
1389
+
zot = z.Zotero("myuserID", "user", "myuserkey")
1390
1390
+
1391
1391
+
# Mock the API response
1392
1392
+
HTTPretty.register_uri(
1393
1393
+
HTTPretty.GET,
1394
1394
+
"https://api.zotero.org/users/myuserID/publications/items",
1395
1395
+
body=self.items_doc,
1396
1396
+
content_type="application/json",
1397
1397
+
)
1398
1398
+
1399
1399
+
# Get publications
1400
1400
+
items = zot.publications()
1401
1401
+
1402
1402
+
# Verify the result
1403
1403
+
self.assertEqual(items[0]["key"], "NM66T6EF")
1404
1404
+
1405
1405
+
def test_publications_group(self):
1406
1406
+
"""Test that publications method raises error for group libraries"""
1407
1407
+
zot = z.Zotero("myGroupID", "group", "myuserkey")
1408
1408
+
1409
1409
+
# Publications API endpoint doesn't exist for groups
1410
1410
+
with self.assertRaises(z.ze.CallDoesNotExistError):
1411
1411
+
zot.publications()
1199
1412
1200
1413
1201
1414
if __name__ == "__main__":