This commit is contained in:
Charles Henry 2018-05-18 13:40:39 +01:00
commit 4cef534271
11 changed files with 1112 additions and 1004 deletions

File diff suppressed because it is too large Load Diff

3
test.sh Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/sh
python -m unittest discover -v tests

61
tests/test_cards.py Executable file
View File

@ -0,0 +1,61 @@
#!/usr/bin/env python
import unittest
import util
class TestCards(unittest.TestCase):
def setUp(self):
util.invoke('createDeck', deck='test')
note = {'deckName': 'test', 'modelName': 'Basic', 'fields': {'Front': 'front1', 'Back': 'back1'}, 'tags': ['tag1']}
self.noteId = util.invoke('addNote', note=note)
def tearDown(self):
util.invoke('deleteDecks', decks=['test'], cardsToo=True)
def runTest(self):
# findCards
cardIds = util.invoke('findCards', query='deck:test')
self.assertEqual(len(cardIds), 1)
# suspend
util.invoke('suspend', cards=cardIds)
# areSuspended (part 1)
suspendedStates = util.invoke('areSuspended', cards=cardIds)
self.assertEqual(len(cardIds), len(suspendedStates))
self.assertNotIn(False, suspendedStates)
# unsuspend
util.invoke('unsuspend', cards=cardIds)
# areSuspended (part 2)
suspendedStates = util.invoke('areSuspended', cards=cardIds)
self.assertEqual(len(cardIds), len(suspendedStates))
self.assertNotIn(True, suspendedStates)
# areDue
dueStates = util.invoke('areDue', cards=cardIds)
self.assertEqual(len(cardIds), len(dueStates))
self.assertNotIn(False, dueStates)
# getIntervals
util.invoke('getIntervals', cards=cardIds, complete=True)
util.invoke('getIntervals', cards=cardIds, complete=False)
# cardsToNotes
noteIds = util.invoke('cardsToNotes', cards=cardIds)
self.assertEqual(len(noteIds), len(cardIds))
self.assertIn(self.noteId, noteIds)
# cardsInfo
cardsInfo = util.invoke('cardsInfo', cards=cardIds)
self.assertEqual(len(cardsInfo), len(cardIds))
for i, cardInfo in enumerate(cardsInfo):
self.assertEqual(cardInfo['cardId'], cardIds[i])
if __name__ == '__main__':
unittest.main()

77
tests/test_decks.py Normal file → Executable file
View File

@ -1,16 +1,71 @@
# -*- coding: utf-8 -*- #!/usr/bin/env python
import unittest import unittest
from unittest import TestCase import util
from util import callAnkiConnectEndpoint
class TestDeckNames(TestCase):
def test_deckNames(self): class TestDecks(unittest.TestCase):
response = callAnkiConnectEndpoint({'action': 'deckNames'}) def runTest(self):
self.assertEqual(['Default'], response) # deckNames (part 1)
deckNames = util.invoke('deckNames')
self.assertIn('Default', deckNames)
class TestGetDeckConfig(TestCase): # deckNamesAndIds
result = util.invoke('deckNamesAndIds')
self.assertIn('Default', result)
self.assertEqual(result['Default'], 1)
def test_getDeckConfig(self): # createDeck
response = callAnkiConnectEndpoint({'action': 'getDeckConfig', 'params': {'deck': 'Default'}}) util.invoke('createDeck', deck='test1')
self.assertDictContainsSubset({'name': 'Default', 'replayq': True}, response)
# deckNames (part 2)
deckNames = util.invoke('deckNames')
self.assertIn('test1', deckNames)
# changeDeck
note = {'deckName': 'test1', 'modelName': 'Basic', 'fields': {'Front': 'front', 'Back': 'back'}, 'tags': ['tag']}
noteId = util.invoke('addNote', note=note)
cardIds = util.invoke('findCards', query='deck:test1')
util.invoke('changeDeck', cards=cardIds, deck='test2')
# deckNames (part 3)
deckNames = util.invoke('deckNames')
self.assertIn('test2', deckNames)
# deleteDecks
util.invoke('deleteDecks', decks=['test1', 'test2'], cardsToo=True)
# deckNames (part 4)
deckNames = util.invoke('deckNames')
self.assertNotIn('test1', deckNames)
self.assertNotIn('test2', deckNames)
# getDeckConfig
deckConfig = util.invoke('getDeckConfig', deck='Default')
self.assertEqual('Default', deckConfig['name'])
# saveDeckConfig
deckConfig = util.invoke('saveDeckConfig', config=deckConfig)
# setDeckConfigId
setDeckConfigId = util.invoke('setDeckConfigId', decks=['Default'], configId=1)
self.assertTrue(setDeckConfigId)
# cloneDeckConfigId (part 1)
deckConfigId = util.invoke('cloneDeckConfigId', cloneFrom=1, name='test')
self.assertTrue(deckConfigId)
# removeDeckConfigId (part 1)
removedDeckConfigId = util.invoke('removeDeckConfigId', configId=deckConfigId)
self.assertTrue(removedDeckConfigId)
# removeDeckConfigId (part 2)
removedDeckConfigId = util.invoke('removeDeckConfigId', configId=deckConfigId)
self.assertFalse(removedDeckConfigId)
# cloneDeckConfigId (part 2)
deckConfigId = util.invoke('cloneDeckConfigId', cloneFrom=deckConfigId, name='test')
self.assertFalse(deckConfigId)
if __name__ == '__main__':
unittest.main()

41
tests/test_graphical.py Executable file
View File

@ -0,0 +1,41 @@
#!/usr/bin/env python
import unittest
import util
class TestGui(unittest.TestCase):
def runTest(self):
# guiBrowse
util.invoke('guiBrowse', query='deck:Default')
# guiAddCards
util.invoke('guiAddCards')
# guiCurrentCard
# util.invoke('guiCurrentCard')
# guiStartCardTimer
util.invoke('guiStartCardTimer')
# guiShowQuestion
util.invoke('guiShowQuestion')
# guiShowAnswer
util.invoke('guiShowAnswer')
# guiAnswerCard
util.invoke('guiAnswerCard', ease=1)
# guiDeckOverview
util.invoke('guiDeckOverview', name='Default')
# guiDeckBrowser
util.invoke('guiDeckBrowser')
# guiExitAnki
# util.invoke('guiExitAnki')
if __name__ == '__main__':
unittest.main()

28
tests/test_media.py Executable file
View File

@ -0,0 +1,28 @@
#!/usr/bin/env python
import unittest
import util
class TestMedia(unittest.TestCase):
def runTest(self):
filename = '_test.txt'
data = 'test'
# storeMediaFile
util.invoke('storeMediaFile', filename='_test.txt', data=data)
# retrieveMediaFile (part 1)
media = util.invoke('retrieveMediaFile', filename=filename)
self.assertEqual(media, data)
# deleteMediaFile
util.invoke('deleteMediaFile', filename=filename)
# retrieveMediaFile (part 2)
media = util.invoke('retrieveMediaFile', filename=filename)
self.assertFalse(media)
if __name__ == '__main__':
unittest.main()

32
tests/test_misc.py Normal file → Executable file
View File

@ -1,10 +1,28 @@
# -*- coding: utf-8 -*- #!/usr/bin/env python
import unittest import unittest
from unittest import TestCase import util
from util import callAnkiConnectEndpoint
class TestVersion(TestCase):
def test_version(self): class TestMisc(unittest.TestCase):
response = callAnkiConnectEndpoint({'action': 'version'}) def runTest(self):
self.assertEqual(5, response) # version
self.assertEqual(util.invoke('version'), 5)
# upgrade
util.invoke('upgrade')
# sync
util.invoke('sync')
# multi
actions = [util.request('version'), util.request('version'), util.request('version')]
results = util.invoke('multi', actions=actions)
self.assertEqual(len(results), len(actions))
for result in results:
self.assertIsNone(result['error'])
self.assertEqual(result['result'], 5)
if __name__ == '__main__':
unittest.main()

25
tests/test_models.py Executable file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env python
import unittest
import util
class TestModels(unittest.TestCase):
def runTest(self):
# modelNames
modelNames = util.invoke('modelNames')
self.assertGreater(len(modelNames), 0)
# modelNamesAndIds
modelNamesAndIds = util.invoke('modelNamesAndIds')
self.assertGreater(len(modelNames), 0)
# modelFieldNames
modelFields = util.invoke('modelFieldNames', modelName=modelNames[0])
# modelFieldsOnTemplates
modelFieldsOnTemplates = util.invoke('modelFieldsOnTemplates', modelName=modelNames[0])
if __name__ == '__main__':
unittest.main()

89
tests/test_notes.py Executable file
View File

@ -0,0 +1,89 @@
#!/usr/bin/env python
import unittest
import util
class TestNotes(unittest.TestCase):
def setUp(self):
util.invoke('createDeck', deck='test')
def tearDown(self):
util.invoke('deleteDecks', decks=['test'], cardsToo=True)
def runTest(self):
# addNote
note = {'deckName': 'test', 'modelName': 'Basic', 'fields': {'Front': 'front1', 'Back': 'back1'}, 'tags': ['tag1']}
noteId = util.invoke('addNote', note=note)
self.assertRaises(Exception, lambda: util.invoke('addNote', note=note))
# addTags
util.invoke('addTags', notes=[noteId], tags='tag2')
# notesInfo (part 1)
noteInfos = util.invoke('notesInfo', notes=[noteId])
self.assertEqual(len(noteInfos), 1)
noteInfo = noteInfos[0]
self.assertEqual(noteInfo['noteId'], noteId)
self.assertSetEqual(set(noteInfo['tags']), {'tag1', 'tag2'})
self.assertEqual(noteInfo['fields']['Front']['value'], 'front1')
self.assertEqual(noteInfo['fields']['Back']['value'], 'back1')
# getTags
allTags = util.invoke('getTags')
self.assertIn('tag1', allTags)
self.assertIn('tag2', allTags)
# removeTags
util.invoke('removeTags', notes=[noteId], tags='tag2')
# updateNoteFields
noteUpdate = {'id': noteId, 'fields': {'Front': 'front2', 'Back': 'back2'}}
util.invoke('updateNoteFields', note=noteUpdate)
# notesInfo (part 2)
noteInfos = util.invoke('notesInfo', notes=[noteId])
self.assertEqual(len(noteInfos), 1)
noteInfo = noteInfos[0]
self.assertSetEqual(set(noteInfo['tags']), {'tag1'})
self.assertIn('tag1', noteInfo['tags'])
self.assertNotIn('tag2', noteInfo['tags'])
self.assertEqual(noteInfo['fields']['Front']['value'], 'front2')
self.assertEqual(noteInfo['fields']['Back']['value'], 'back2')
notes = [
{'deckName': 'test', 'modelName': 'Basic', 'fields': {'Front': 'front3', 'Back': 'back3'}, 'tags': ['tag']},
{'deckName': 'test', 'modelName': 'Basic', 'fields': {'Front': 'front4', 'Back': 'back4'}, 'tags': ['tag']}
]
# canAddNotes (part 1)
noteStates = util.invoke('canAddNotes', notes=notes)
self.assertEqual(len(noteStates), len(notes))
self.assertNotIn(False, noteStates)
# addNotes (part 1)
noteIds = util.invoke('addNotes', notes=notes)
self.assertEqual(len(noteIds), len(notes))
for noteId in noteIds:
self.assertNotEqual(noteId, None)
# canAddNotes (part 2)
noteStates = util.invoke('canAddNotes', notes=notes)
self.assertNotIn(True, noteStates)
self.assertEqual(len(noteStates), len(notes))
# addNotes (part 2)
noteIds = util.invoke('addNotes', notes=notes)
self.assertEqual(len(noteIds), len(notes))
for noteId in noteIds:
self.assertEqual(noteId, None)
# findNotes
noteIds = util.invoke('findNotes', query='deck:test')
self.assertEqual(len(noteIds), len(notes) + 1)
if __name__ == '__main__':
unittest.main()

View File

@ -1,11 +1,23 @@
import json import json
import urllib
import urllib2 import urllib2
def callAnkiConnectEndpoint(data): API_VERSION = 5
url = 'http://docker:8888' API_URL = 'http://localhost:8765'
dumpedData = json.dumps(data)
req = urllib2.Request(url, dumpedData)
response = urllib2.urlopen(req).read() def request(action, **params):
responseData = json.loads(response) return {'action': action, 'params': params, 'version': API_VERSION}
return responseData
def invoke(action, **params):
requestJson = json.dumps(request(action, **params))
response = json.load(urllib2.urlopen(urllib2.Request(API_URL, requestJson)))
if len(response) != 2:
raise Exception('response has an unexpected number of fields')
if 'error' not in response:
raise Exception('response is missing required error field')
if 'result' not in response:
raise Exception('response is missing required result field')
if response['error'] is not None:
raise Exception(response['error'])
return response['result']