Merge branch 'master' of https://github.com/FooSoft/anki-connect
This commit is contained in:
commit
4cef534271
1730
AnkiConnect.py
1730
AnkiConnect.py
File diff suppressed because it is too large
Load Diff
3
test.sh
Executable file
3
test.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/usr/bin/sh
|
||||
|
||||
python -m unittest discover -v tests
|
61
tests/test_cards.py
Executable file
61
tests/test_cards.py
Executable 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()
|
79
tests/test_decks.py
Normal file → Executable file
79
tests/test_decks.py
Normal file → Executable file
@ -1,16 +1,71 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#!/usr/bin/env python
|
||||
|
||||
import unittest
|
||||
from unittest import TestCase
|
||||
from util import callAnkiConnectEndpoint
|
||||
import util
|
||||
|
||||
class TestDeckNames(TestCase):
|
||||
|
||||
def test_deckNames(self):
|
||||
response = callAnkiConnectEndpoint({'action': 'deckNames'})
|
||||
self.assertEqual(['Default'], response)
|
||||
class TestDecks(unittest.TestCase):
|
||||
def runTest(self):
|
||||
# deckNames (part 1)
|
||||
deckNames = util.invoke('deckNames')
|
||||
self.assertIn('Default', deckNames)
|
||||
|
||||
class TestGetDeckConfig(TestCase):
|
||||
|
||||
def test_getDeckConfig(self):
|
||||
response = callAnkiConnectEndpoint({'action': 'getDeckConfig', 'params': {'deck': 'Default'}})
|
||||
self.assertDictContainsSubset({'name': 'Default', 'replayq': True}, response)
|
||||
# deckNamesAndIds
|
||||
result = util.invoke('deckNamesAndIds')
|
||||
self.assertIn('Default', result)
|
||||
self.assertEqual(result['Default'], 1)
|
||||
|
||||
# createDeck
|
||||
util.invoke('createDeck', deck='test1')
|
||||
|
||||
# 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
41
tests/test_graphical.py
Executable 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
28
tests/test_media.py
Executable 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
32
tests/test_misc.py
Normal file → Executable file
@ -1,10 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#!/usr/bin/env python
|
||||
|
||||
import unittest
|
||||
from unittest import TestCase
|
||||
from util import callAnkiConnectEndpoint
|
||||
import util
|
||||
|
||||
class TestVersion(TestCase):
|
||||
|
||||
def test_version(self):
|
||||
response = callAnkiConnectEndpoint({'action': 'version'})
|
||||
self.assertEqual(5, response)
|
||||
class TestMisc(unittest.TestCase):
|
||||
def runTest(self):
|
||||
# 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
25
tests/test_models.py
Executable 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
89
tests/test_notes.py
Executable 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()
|
@ -1,11 +1,23 @@
|
||||
import json
|
||||
import urllib
|
||||
import urllib2
|
||||
|
||||
def callAnkiConnectEndpoint(data):
|
||||
url = 'http://docker:8888'
|
||||
dumpedData = json.dumps(data)
|
||||
req = urllib2.Request(url, dumpedData)
|
||||
response = urllib2.urlopen(req).read()
|
||||
responseData = json.loads(response)
|
||||
return responseData
|
||||
API_VERSION = 5
|
||||
API_URL = 'http://localhost:8765'
|
||||
|
||||
|
||||
def request(action, **params):
|
||||
return {'action': action, 'params': params, 'version': API_VERSION}
|
||||
|
||||
|
||||
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']
|
||||
|
Loading…
Reference in New Issue
Block a user