247 lines
10 KiB
Python
247 lines
10 KiB
Python
import gzip
|
|
import ujson as json
|
|
import unittest
|
|
from wanikaniburned import app, db
|
|
from wanikaniburned.wanikaniburned import User, datetime_format, parse_range
|
|
from flask.ext.testing import TestCase
|
|
from datetime import datetime
|
|
|
|
|
|
class BaseTestCase(TestCase):
|
|
|
|
def create_app(self):
|
|
app.config.update(
|
|
TESTING=True,
|
|
SQLALCHEMY_DATABASE_URI='sqlite:///:memory:',
|
|
SECRET_KEY="testkey",
|
|
WTF_CSRF_ENABLED=False,
|
|
PRESERVE_CONTEXT_ON_EXCEPTION=False,
|
|
HASH_ROUNDS=1
|
|
)
|
|
return app
|
|
|
|
def setUp(self):
|
|
db.create_all()
|
|
|
|
def tearDown(self):
|
|
db.session.remove()
|
|
db.drop_all()
|
|
|
|
|
|
class TestLogin(BaseTestCase):
|
|
|
|
def login(self):
|
|
user = User('test', False)
|
|
return self.client.post('/', data={'api_key': user.api_key})
|
|
|
|
def test_user_login(self):
|
|
response = self.login()
|
|
self.assertRedirects(response, '/quiz')
|
|
|
|
def test_user_logout(self):
|
|
response = self.login()
|
|
self.assertRedirects(response, '/quiz')
|
|
response = self.client.get('/logout')
|
|
self.assertRedirects(response, '/')
|
|
|
|
def test_homepage_without_login(self):
|
|
response = self.client.get('/')
|
|
self.assert200(response)
|
|
self.assertTemplateUsed("welcome.html")
|
|
|
|
def test_quiz_inaccessible_without_login(self):
|
|
response = self.client.get('/quiz')
|
|
self.assertRedirects(response, '/')
|
|
|
|
def test_quiz_accessible_with_login(self):
|
|
self.login()
|
|
response = self.client.get('/quiz')
|
|
self.assert200(response)
|
|
self.assertTemplateUsed("quiz.html")
|
|
|
|
def test_user_items_inaccessible_without_login(self):
|
|
response = self.client.get('/user_items')
|
|
self.assertRedirects(response, '/')
|
|
|
|
def test_homepage_with_existing_login(self):
|
|
response = self.login() # Login
|
|
self.assertRedirects(response, '/quiz')
|
|
response = self.client.get('/') # Try to go back to the homepage
|
|
self.assertRedirects(response, '/quiz')
|
|
|
|
def test_user_items_with_existing_login(self):
|
|
response = self.login() # Login
|
|
self.assertRedirects(response, '/quiz')
|
|
response = self.client.get('/user_items')
|
|
self.assert200(response)
|
|
|
|
def test_login_with_username(self):
|
|
user = User('test', False, "alternate")
|
|
response = self.client.post('/', data={'api_key': user.username})
|
|
self.assertRedirects(response, '/quiz')
|
|
|
|
def test_login_same_username_new_api_key(self):
|
|
user = User('test', False, "alternate")
|
|
changed_user = User('newapikey', False, "alternate")
|
|
self.assertTrue(User.query.get(changed_user.api_key))
|
|
self.assertFalse(User.query.get(user.api_key))
|
|
response = self.client.post('/', data={'api_key': user.username})
|
|
self.assertRedirects(response, '/quiz')
|
|
|
|
|
|
class TestFormats(unittest.TestCase):
|
|
|
|
def test_custom_datetime_format(self):
|
|
test_time = datetime.min
|
|
output = datetime_format(test_time)
|
|
self.assertEqual(output, test_time.strftime("%d %B %Y %I:%M%p"))
|
|
|
|
def test_parse_range_empty(self):
|
|
self.assertIsNone(parse_range(""))
|
|
|
|
def test_parse_range_letters(self):
|
|
self.assertIsNone(parse_range("ab-st,z"))
|
|
|
|
def test_parse_range_single_number(self):
|
|
self.assertEqual(parse_range("1"), [1])
|
|
|
|
def test_parse_range_two_with_dash(self):
|
|
self.assertEqual(parse_range("1-4"), [1, 2, 3, 4])
|
|
|
|
def test_parse_range_two_with_comma(self):
|
|
self.assertEqual(parse_range("1,2"), [1, 2])
|
|
|
|
def test_parse_range_dash_and_comma(self):
|
|
self.assertEqual(parse_range("1,4-6"), [1, 4, 5, 6])
|
|
|
|
|
|
class TestUserItems(BaseTestCase):
|
|
|
|
with gzip.open("testuserdata.json.gz", "rb") as input_file:
|
|
user_data = json.loads(input_file.read().decode('utf8'))
|
|
user_radicals = user_data['radicals']
|
|
user_kanji = user_data['kanji']
|
|
user_vocabulary = user_data['vocabulary']
|
|
|
|
def get_user(self):
|
|
user = User('test', False)
|
|
user.radicals = json.dumps(self.user_radicals, ensure_ascii=False)
|
|
user.kanji = json.dumps(self.user_kanji, ensure_ascii=False)
|
|
user.vocabulary = json.dumps(self.user_vocabulary, ensure_ascii=False)
|
|
return user
|
|
|
|
def login(self, user):
|
|
return self.client.post('/', data={'api_key': user.api_key})
|
|
|
|
def count_filter(self, item_list, item_type=None, level_range=list(range(0, 61))):
|
|
if item_type is None:
|
|
item_type = ['burned']
|
|
return sum(1 for item in item_list if item['user_specific'] and item['user_specific']['srs'] in item_type
|
|
and item['level'] in level_range)
|
|
|
|
def flatten_list_to_string(self, input_list):
|
|
return ",".join(map(str, input_list))
|
|
|
|
def test_count_default(self):
|
|
user = self.get_user()
|
|
self.login(user)
|
|
response = self.client.get('/user_items')
|
|
response = json.loads(response.data)
|
|
self.assertEqual(response['radical_count'], self.count_filter(self.user_radicals))
|
|
self.assertEqual(response['kanji_count'], self.count_filter(self.user_kanji))
|
|
self.assertEqual(response['vocabulary_count'], self.count_filter(self.user_vocabulary))
|
|
|
|
def test_filter_single_type(self):
|
|
user = self.get_user()
|
|
self.login(user)
|
|
response = self.client.get('/user_items?item_types=radical')
|
|
response = json.loads(response.data)
|
|
self.assertEqual(response['radical_count'], self.count_filter(self.user_radicals))
|
|
self.assertEqual(response['kanji_count'], 0)
|
|
self.assertEqual(response['vocabulary_count'], 0)
|
|
|
|
def test_filter_double_type(self):
|
|
user = self.get_user()
|
|
self.login(user)
|
|
response = self.client.get('/user_items?item_types=radical,kanji')
|
|
response = json.loads(response.data)
|
|
self.assertEqual(response['radical_count'], self.count_filter(self.user_radicals))
|
|
self.assertEqual(response['kanji_count'], self.count_filter(self.user_kanji))
|
|
self.assertEqual(response['vocabulary_count'], 0)
|
|
|
|
def test_filter_all_type(self):
|
|
user = self.get_user()
|
|
self.login(user)
|
|
response = self.client.get('/user_items?item_types=radical,kanji,vocab')
|
|
response = json.loads(response.data)
|
|
self.assertEqual(response['radical_count'], self.count_filter(self.user_radicals))
|
|
self.assertEqual(response['kanji_count'], self.count_filter(self.user_kanji))
|
|
self.assertEqual(response['vocabulary_count'], self.count_filter(self.user_vocabulary))
|
|
|
|
def test_filter_invalid_type(self):
|
|
user = self.get_user()
|
|
self.login(user)
|
|
response = self.client.get('/user_items?item_types=invalid')
|
|
response = json.loads(response.data)
|
|
self.assertEqual(response, dict(error='No items within these filter parameters'))
|
|
|
|
def test_filter_single_level(self):
|
|
test_data = [1]
|
|
user = self.get_user()
|
|
self.login(user)
|
|
response = self.client.get('/user_items?level_range=' + (self.flatten_list_to_string(test_data)))
|
|
response = json.loads(response.data)
|
|
self.assertEqual(response['radical_count'], self.count_filter(self.user_radicals, level_range=test_data))
|
|
self.assertEqual(response['kanji_count'], self.count_filter(self.user_kanji, level_range=test_data))
|
|
self.assertEqual(response['vocabulary_count'], self.count_filter(self.user_vocabulary, level_range=test_data))
|
|
|
|
def test_filter_multiple_levels(self):
|
|
test_data = [1, 2, 4]
|
|
user = self.get_user()
|
|
self.login(user)
|
|
response = self.client.get('/user_items?level_range=' + (self.flatten_list_to_string(test_data)))
|
|
response = json.loads(response.data)
|
|
self.assertEqual(response['radical_count'], self.count_filter(self.user_radicals, level_range=test_data))
|
|
self.assertEqual(response['kanji_count'], self.count_filter(self.user_kanji, level_range=test_data))
|
|
self.assertEqual(response['vocabulary_count'], self.count_filter(self.user_vocabulary, level_range=test_data))
|
|
|
|
def test_filter_invalid_levels(self):
|
|
test_data = [0, 61, 1000]
|
|
user = self.get_user()
|
|
self.login(user)
|
|
response = self.client.get('/user_items?level_range=' + (self.flatten_list_to_string(test_data)))
|
|
response = json.loads(response.data)
|
|
self.assertEqual(response, dict(error='No items within these filter parameters'))
|
|
|
|
def test_filter_single_state(self):
|
|
test_data = ['enlighten']
|
|
user = self.get_user()
|
|
self.login(user)
|
|
response = self.client.get('/user_items?item_state=' + (self.flatten_list_to_string(test_data)))
|
|
response = json.loads(response.data)
|
|
self.assertEqual(response['radical_count'], self.count_filter(self.user_radicals, test_data))
|
|
self.assertEqual(response['kanji_count'], self.count_filter(self.user_kanji, test_data))
|
|
self.assertEqual(response['vocabulary_count'], self.count_filter(self.user_vocabulary, test_data))
|
|
|
|
def test_filter_multiple_state(self):
|
|
test_data = ['guru', 'master', 'apprentice']
|
|
user = self.get_user()
|
|
self.login(user)
|
|
response = self.client.get('/user_items?item_state=' + (self.flatten_list_to_string(test_data)))
|
|
response = json.loads(response.data)
|
|
self.assertEqual(response['radical_count'], self.count_filter(self.user_radicals, test_data))
|
|
self.assertEqual(response['kanji_count'], self.count_filter(self.user_kanji, test_data))
|
|
self.assertEqual(response['vocabulary_count'], self.count_filter(self.user_vocabulary, test_data))
|
|
|
|
def test_filter_invalid_state(self):
|
|
test_data = ['invalid', 'alsoinvalid']
|
|
user = self.get_user()
|
|
self.login(user)
|
|
response = self.client.get('/user_items?item_state=' + (self.flatten_list_to_string(test_data)))
|
|
response = json.loads(response.data)
|
|
self.assertEqual(response, dict(error='No items within these filter parameters'))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|