import gzip import ujson as json import unittest from wanikaniburned import app, db, 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, "01 January 1 12:00AM") 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()