<commit_before>from __future__ import (
        absolute_import, division, print_function, unicode_literals)
from builtins import (ascii, bytes, chr, dict, filter, hex, input,  # noqa
                      int, map, next, oct, open, pow, range, round,
                      str, super, zip)

from contextlib import contextmanager
from itertools import chain
from mock import ANY, Mock, patch
import re
import unittest
import time

from flask import flash, render_template, session, url_for
import flask.ext.testing
import requests

from .. import main
from ..main import Game, User, db


class TestWithTestingApp(flask.ext.testing.TestCase):

    def create_app(self):
        main.app.config['TESTING'] = True
        main.app.config['WTF_CSRF_ENABLED'] = False
        return main.app

    def setUp(self):
        self.test_client = main.app.test_client()

    @contextmanager
    def set_user(self, user=None):
        """Set the logged in user value in the session object."""
        if user is None:
            user = self.LOGGED_IN_EMAIL
        with main.app.test_client() as test_client:
            with test_client.session_transaction() as session:
                session['user'] = user
            yield test_client

    @contextmanager
    def patch_render_template(self):
        """Patch out render_template with a mock.

        Use when the return value of the view is not important to the test;
        rendering templates uses a ton of runtime."""
        mock_render = Mock(spec=render_template)
        mock_render.return_value = ''
        with patch('app.main.render_template', mock_render):
            yield mock_render

    @contextmanager
    def assert_flashes(self, snippet, message=None):
        """Assert that the following code creates a Flask flash message.

        The message must contain the given snippet to pass."""
        if message is None:
            message = "'{}' not found in any flash message".format(snippet)
        mock_flash = Mock(spec=flash)
        with patch('app.main.flash', mock_flash):
            yield mock_flash
        for call_args in mock_flash.call_args_list:
            args, _ = call_args
            if snippet.lower() in args[0].lower():
                return
        self.fail(message)


class TestWithDb(TestWithTestingApp):

    def create_app(self):
        main.app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
        return super().create_app()

    def setUp(self):
        super().setUp()
        main.db.session.remove()
        main.db.drop_all()
        main.db.create_all()

    def tearDown(self):
        main.db.session.remove()
        main.db.drop_all()
        super().tearDown()

    def add_game(self, sgf_or_stones=None, stones=None, sgf=None,
                 black='<EMAIL>', white='<EMAIL>',
                 finished=False):
        game = main.create_game_internal(
            black=black, white=white,
            sgf_or_stones=sgf_or_stones, stones=stones, sgf=sgf)
        if finished:
            game.finished = True
        return game


class TestFrontPageIntegrated(TestWithTestingApp):

    def test_without_login_shows_persona_login_link(self):
        response = self.test_client.get('/')
        assert re.search(
                r"""<a [^>]*id=['"]persona_login['"]""",
                str(response.get_data())) is not None

    def test_with_login_redirects_to_status(self):
        with self.set_user('<EMAIL>') as test_client:
            response = test_client.get('/')
        self.assert_redirects(response, url_for('status'))


class TestNativeLoginIntegrated(TestWithDb):

    def test_unknown_username(self):
        self.assertEqual(db.session.query(User).count(), 0)
        db.session.add(User(username='bill', password='<PASSWORD>'))
        db.session.commit()
        with main.app.test_client() as test_client:
            with self.assert_flashes('not found'):

                response = test_client.post(url_for('login'),
                                            data=dict(username='ted',
                                                      password='<PASSWORD>'))

            self.assertFalse(main.is_logged_in())
        self.assert_redirects(response, '/')

    def test_bad_password(self):
        db.session.add(User(username='rufus', password='<PASSWORD>'))
        db.session.commit()
        with main.app.test_client() as test_client:
            with self.assert_flashes('incorrect'):

                response = test_client.post(url_for('login'),
                                            data=dict(username='rufus',
                                                      password='<PASSWORD>'))

            self.assertFalse(main.is_logged_in())
        self.assert_redirects(response, '/')

    def test_good_login(self):
        db.session.add(User(username='rufus', password='<PASSWORD>'))
        db.session.commit()
        with main.app.test_client() as test_client:
            self.assertFalse(main.is_logged_in())

            response = test_client.post(url_for('login'),
                                        data=dict(username='rufus',
                                                  password='<PASSWORD>'))

            self.assertTrue(main.is_logged_in())
            self.assertEqual(main.logged_in_user(), 'rufus')
        self.assert_redirects(response, '/')


class TestPersonaLoginIntegrated(TestWithTestingApp):

    TEST_EMAIL = '<EMAIL>'

    def make_mock_post(self, ok=True, status='okay', email=TEST_EMAIL):
        mock_post = Mock(spec=requests.post)
        mock_post.return_value = Mock()
        mock_post.return_value.ok = ok
        mock_post.return_value.json.return_value = {
                'status': status,
                'email': email,
        }
        return mock_post

    def post_simple_assertion(self, test_client=None, mock_post=None):
        if test_client is None:
            test_client = self.test_client
        if mock_post is None:
            mock_post = self.make_mock_post()
        with patch('app.main.requests.post', mock_post):
            response = test_client.post('/persona/login',
                                        data={'assertion': 'test'})
        return (response, mock_post)


    def test_aborts_on_no_assertion(self):
        response = self.test_client.post('/persona/login',
                                         data={})
        self.assertEqual(response.status_code, 400)

    def test_posts_assertion_to_mozilla(self):
        _, mock_post = self.post_simple_assertion()
        mock_post.assert_called_once_with(
                'https://verifier.login.persona.org/verify',
                data={
                    'assertion': 'test',
                    'audience': ANY
                },
                verify=True
        )

    def test_good_response_sets_session_email_and_persona_email(self):
        with main.app.test_client() as test_client:

            self.post_simple_assertion(test_client)

            self.assertEqual(main.logged_in_user(), self.TEST_EMAIL)
            self.assertEqual(session['persona_email'], self.TEST_EMAIL)

    def test_bad_response_status_aborts(self):
        mock_post = self.make_mock_post(status='no no NO')
        with main.app.test_client() as test_client:

            response, _ = self.post_simple_assertion(test_client, mock_post)

            self.assertFalse(main.is_logged_in())
            self.assertNotEqual(response.status_code, 200)

    def test_bad_response_ok_aborts(self):
        mock_post = self.make_mock_post(ok=False)
        with main.app.test_client() as test_client:

            response, _ = self.post_simple_assertion(test_client, mock_post)

            self.assertFalse(main.is_logged_in())
            self.assertNotEqual(response.status_code, 200)


class TestLogoutIntegrated(TestWithTestingApp):

    def test_no_content_on_post(self):
        response = self.test_client.post(url_for('logout'))
        self.assertEqual(len(response.data), 0)

    def test_returns_to_front_on_get(self):
        response = self.test_client.get(url_for('logout'))
        self.assert_redirects(response, '/')

    def test_removes_email_and_persona_email_from_session(self):
        with main.app.test_client() as test_client:
            with test_client.session_transaction() as session:
                main.set_logged_in_user('<EMAIL>')
                session['persona_email'] = '<EMAIL>'
            with self.patch_render_template():

                test_client.post('/logout')

            with test_client.session_transaction() as session:
                self.assertFalse(main.is_logged_in())
                self.assertNotIn('persona_email', session)

    def test_no_error_when_email_not_set(self):
        with main.app.test_client() as test_client:
            try:
                with self.patch_render_template():
                    test_client.post('/logout')
            except Exception as e:
                self.fail("exception {} raised for logout "
                          "with no email set".format(repr(e)))


class TestChallengeIntegrated(TestWithDb):

    def test_get_form(self):
        with self.set_user('<EMAIL>') as test_client:
            test_client.get(url_for('challenge'))
        # should not raise

    def test_good_post_creates_game(self):
        assert Game.query.all() == []
        with self.set_user('<EMAIL>') as test_client:
            test_client.post('/challenge', data=dict(
                opponent='<EMAIL>'))
        game = db.session.query(Game).one()
        self.assertEqual(game.white, '<EMAIL>')
        self.assertEqual(game.black, '<EMAIL>')
        self.assertIn("(;", game.sgf)
        self.assertFalse(game.finished)


class TestCreateAccountIntegrated(TestWithDb):

    def test_get_request_shows_form(self):
        with self.patch_render_template() as mock_render:
            self.test_client.get(url_for('create_account'))
            args, kwargs = mock_render.call_args
            self.assertEqual('create_account.html', args[0])

    def test_good_post_creates_account_and_logs_in(self):
        self.assertEqual(db.session.query(User).count(), 0)
        with main.app.test_client() as test_client:
            self.assertFalse(main.is_logged_in())
            with self.patch_render_template():
                test_client.post(url_for('create_account'),
                                 data=dict(username='freddy',
                                           password1='<PASSWORD>',
                                           password2='<PASSWORD>'))
            self.assertTrue(main.is_logged_in())
            self.assertEqual(main.logged_in_user(), 'freddy')
        db.session.rollback()  # to catch missing commits
        user = db.session.query(User).one()
        self.assertEqual(user.username, 'freddy')
        self.assertTrue(user.check_password('<PASSWORD>'))

    def test_non_matching_passwords(self):
        with main.app.test_client() as test_client:
            with self.assert_flashes("do not match"):
                with self.patch_render_template() as mock_render:
                    test_client.post(url_for('create_account'),
                                     data=dict(username='freddy',
                                               password1='<PASSWORD>',
                                               password2='<PASSWORD>'))
                    args, kwargs = mock_render.call_args
                    self.assertEqual('create_account.html', args[0])
            self.assertFalse(main.is_logged_in())


class TestStatusIntegrated(TestWithDb):

    def count_pattern_in(self, pattern, string):
        return len(re.split(pattern, string)) - 1

    def setup_test_games(self):
        self.LOGGED_IN_EMAIL = '<EMAIL>'
        OTHER_EMAIL_1 = '<EMAIL>'
        OTHER_EMAIL_2 = '<EMAIL>'
        game1 = self.add_game(black=self.LOGGED_IN_EMAIL, white=OTHER_EMAIL_1)
        game2 = self.add_game(black=OTHER_EMAIL_1, white=OTHER_EMAIL_2)
        game3 = self.add_game(black=OTHER_EMAIL_1, white=self.LOGGED_IN_EMAIL)
        game4 = self.add_game(black=OTHER_EMAIL_1, white=self.LOGGED_IN_EMAIL,
                              sgf="(;B[jj])")
        game5 = self.add_game(black=OTHER_EMAIL_1, white=self.LOGGED_IN_EMAIL,
                              sgf="(;B[])")
        game6 = self.add_game(black=self.LOGGED_IN_EMAIL, white=OTHER_EMAIL_1,
                              finished=True)
        return (game1, game2, game3, game4, game5, game6,)

    def test_sends_games_to_correct_template_params(self):
        game1, game2, game3, game4, game5, game6 = self.setup_test_games()
        with self.set_user() as test_client:
            with self.patch_render_template() as mock_render:

                test_client.get(url_for('status'))

                args, kwargs = mock_render.call_args
        self.assertEqual(args[0], "status.html")
        your_turn_games = kwargs['your_turn_games']
        not_your_turn_games = kwargs['not_your_turn_games']

        self.assertEqual(set(your_turn_games), set([game1, game4, game5]))
        self.assertEqual(set(not_your_turn_games), set([game3]))

    def test_shows_links_to_existing_games(self):
        self.setup_test_games()
        with self.set_user() as test_client:
            response = test_client.get(url_for('status'))
        self.assertEqual(
                self.count_pattern_in(r"Game \d", str(response.get_data())),
                4)

    def test_anonymous_users_redirected_to_front(self):
        with main.app.test_client() as test_client:
            response = test_client.get(url_for('status'))
        self.assert_redirects(response, '/')

    def test_games_come_out_sorted(self):
        """Regression test: going via dictionaries can break sorting"""
        for i in range(5):
            self.add_game(black='<EMAIL>', white='<EMAIL>')
            self.add_game(black='<EMAIL>', white='<EMAIL>')
        with self.set_user('<EMAIL>') as test_client:
            with self.patch_render_template() as mock_render:

                test_client.get(url_for('status'))

                args, kwargs = mock_render.call_args
        your_turn_games = kwargs['your_turn_games']
        not_your_turn_games = kwargs['not_your_turn_games']

        def game_key(game):
            return game.id
        self.assertEqual(
                your_turn_games,
                sorted(your_turn_games, key=game_key))
        self.assertEqual(
                not_your_turn_games,
                sorted(not_your_turn_games, key=game_key))


class TestFinishedIntegrated(TestWithDb):

    def test_anonymous_users_redirected_to_front(self):
        with main.app.test_client() as test_client:
            response = test_client.get(url_for('finished'))
        self.assert_redirects(response, '/')

    def test_shows_only_finished_games(self):
        black_game = self.add_game(black='<EMAIL>', finished=True)
        white_game = self.add_game(white='<EMAIL>', finished=True)
        self.add_game(black='<EMAIL>', finished=False)
        self.add_game(finished=True)
        with self.set_user('<EMAIL>') as test_client:
            with self.patch_render_template() as mock_render:

                test_client.get(url_for('finished'))

                args, kwargs = mock_render.call_args
        self.assertEqual(args[0], "finished.html")
        finished_games = kwargs['finished_games']
        self.assertEqual(set(finished_games), set([black_game, white_game]))


class TestGameIntegrated(TestWithDb):

    def test_404_if_no_game_specified(self):
        response = self.test_client.get('/game')
        self.assert404(response)

    def test_redirects_to_home_if_game_not_found(self):
        out_of_range = max(chain([0], Game.query.filter(Game.id))) + 1
        with main.app.test_client() as test_client:
            response = test_client.get(url_for('game', game_no=out_of_range))
        self.assert_redirects(response, '/')

    def do_mocked_get(self, game):
        with self.set_user('<EMAIL>') as test_client:
            with self.patch_render_template() as mock_render:
                test_client.get(url_for('game', game_no=game.id))
                return mock_render.call_args

    def test_passes_sgf_in_form(self):
        game = self.add_game(['.b'])
        args, kwargs = self.do_mocked_get(game)
        self.assertIn("B[ba]", kwargs['form'].data.data)

    def test_after_two_passes_activates_scoring_interface(self):
        game = self.add_game("(;B[];W[])")
        args, kwargs = self.do_mocked_get(game)
        self.assertEqual(kwargs['with_scoring'], True)


class TestResignIntegrated(TestWithDb):

    def test_sets_finished(self):
        game = self.add_game()
        self.assertFalse(game.finished,
                         "game should not initially be finished")
        with self.set_user(game.black) as test_client:
            test_client.post(url_for('play', game_no=game.id),
                             data=dict(resign_button='resign'))
        self.assertTrue(game.finished,
                        "game should be finished after resign posted")

    def test_nothing_happens_off_turn(self):
        game = self.add_game()
        self.assertFalse(game.finished,
                         "game should not initially be finished")
        with self.set_user(game.white) as test_client:
            test_client.post(url_for('play', game_no=game.id),
                             data=dict(resign_button='resign'))
        self.assertFalse(game.finished,
                         "game should not be finished")


class TestPlayIntegrated(TestWithDb):

    def test_can_add_stones_and_passes_to_two_games(self):
        game1 = self.add_game()
        game2 = self.add_game()
        with self.patch_render_template():
            with self.set_user('<EMAIL>') as test_client:
                test_client.post(url_for('play', game_no=game1.id),
                                 data=dict(response="(;B[pd])"))<commit_msg>make resign test catch missing commit bug<commit_after>from __future__ import (
        absolute_import, division, print_function, unicode_literals)
from builtins import (ascii, bytes, chr, dict, filter, hex, input,  # noqa
                      int, map, next, oct, open, pow, range, round,
                      str, super, zip)

from contextlib import contextmanager
from itertools import chain
from mock import ANY, Mock, patch
import re
import unittest
import time

from flask import flash, render_template, session, url_for
import flask.ext.testing
import requests

from .. import main
from ..main import Game, User, db


class TestWithTestingApp(flask.ext.testing.TestCase):

    def create_app(self):
        main.app.config['TESTING'] = True
        main.app.config['WTF_CSRF_ENABLED'] = False
        return main.app

    def setUp(self):
        self.test_client = main.app.test_client()

    @contextmanager
    def set_user(self, user=None):
        """Set the logged in user value in the session object."""
        if user is None:
            user = self.LOGGED_IN_EMAIL
        with main.app.test_client() as test_client:
            with test_client.session_transaction() as session:
                session['user'] = user
            yield test_client

    @contextmanager
    def patch_render_template(self):
        """Patch out render_template with a mock.

        Use when the return value of the view is not important to the test;
        rendering templates uses a ton of runtime."""
        mock_render = Mock(spec=render_template)
        mock_render.return_value = ''
        with patch('app.main.render_template', mock_render):
            yield mock_render

    @contextmanager
    def assert_flashes(self, snippet, message=None):
        """Assert that the following code creates a Flask flash message.

        The message must contain the given snippet to pass."""
        if message is None:
            message = "'{}' not found in any flash message".format(snippet)
        mock_flash = Mock(spec=flash)
        with patch('app.main.flash', mock_flash):
            yield mock_flash
        for call_args in mock_flash.call_args_list:
            args, _ = call_args
            if snippet.lower() in args[0].lower():
                return
        self.fail(message)


class TestWithDb(TestWithTestingApp):

    def create_app(self):
        main.app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
        return super().create_app()

    def setUp(self):
        super().setUp()
        main.db.session.remove()
        main.db.drop_all()
        main.db.create_all()

    def tearDown(self):
        main.db.session.remove()
        main.db.drop_all()
        super().tearDown()

    def add_game(self, sgf_or_stones=None, stones=None, sgf=None,
                 black='<EMAIL>', white='<EMAIL>',
                 finished=False):
        game = main.create_game_internal(
            black=black, white=white,
            sgf_or_stones=sgf_or_stones, stones=stones, sgf=sgf)
        if finished:
            game.finished = True
        return game


class TestFrontPageIntegrated(TestWithTestingApp):

    def test_without_login_shows_persona_login_link(self):
        response = self.test_client.get('/')
        assert re.search(
                r"""<a [^>]*id=['"]persona_login['"]""",
                str(response.get_data())) is not None

    def test_with_login_redirects_to_status(self):
        with self.set_user('test@mock<EMAIL>') as test_client:
            response = test_client.get('/')
        self.assert_redirects(response, url_for('status'))


class TestNativeLoginIntegrated(TestWithDb):

    def test_unknown_username(self):
        self.assertEqual(db.session.query(User).count(), 0)
        db.session.add(User(username='bill', password='<PASSWORD>'))
        db.session.commit()
        with main.app.test_client() as test_client:
            with self.assert_flashes('not found'):

                response = test_client.post(url_for('login'),
                                            data=dict(username='ted',
                                                      password='<PASSWORD>'))

            self.assertFalse(main.is_logged_in())
        self.assert_redirects(response, '/')

    def test_bad_password(self):
        db.session.add(User(username='rufus', password='<PASSWORD>'))
        db.session.commit()
        with main.app.test_client() as test_client:
            with self.assert_flashes('incorrect'):

                response = test_client.post(url_for('login'),
                                            data=dict(username='rufus',
                                                      password='<PASSWORD>'))

            self.assertFalse(main.is_logged_in())
        self.assert_redirects(response, '/')

    def test_good_login(self):
        db.session.add(User(username='rufus', password='<PASSWORD>'))
        db.session.commit()
        with main.app.test_client() as test_client:
            self.assertFalse(main.is_logged_in())

            response = test_client.post(url_for('login'),
                                        data=dict(username='rufus',
                                                  password='<PASSWORD>'))

            self.assertTrue(main.is_logged_in())
            self.assertEqual(main.logged_in_user(), 'rufus')
        self.assert_redirects(response, '/')


class TestPersonaLoginIntegrated(TestWithTestingApp):

    TEST_EMAIL = '<EMAIL>'

    def make_mock_post(self, ok=True, status='okay', email=TEST_EMAIL):
        mock_post = Mock(spec=requests.post)
        mock_post.return_value = Mock()
        mock_post.return_value.ok = ok
        mock_post.return_value.json.return_value = {
                'status': status,
                'email': email,
        }
        return mock_post

    def post_simple_assertion(self, test_client=None, mock_post=None):
        if test_client is None:
            test_client = self.test_client
        if mock_post is None:
            mock_post = self.make_mock_post()
        with patch('app.main.requests.post', mock_post):
            response = test_client.post('/persona/login',
                                        data={'assertion': 'test'})
        return (response, mock_post)


    def test_aborts_on_no_assertion(self):
        response = self.test_client.post('/persona/login',
                                         data={})
        self.assertEqual(response.status_code, 400)

    def test_posts_assertion_to_mozilla(self):
        _, mock_post = self.post_simple_assertion()
        mock_post.assert_called_once_with(
                'https://verifier.login.persona.org/verify',
                data={
                    'assertion': 'test',
                    'audience': ANY
                },
                verify=True
        )

    def test_good_response_sets_session_email_and_persona_email(self):
        with main.app.test_client() as test_client:

            self.post_simple_assertion(test_client)

            self.assertEqual(main.logged_in_user(), self.TEST_EMAIL)
            self.assertEqual(session['persona_email'], self.TEST_EMAIL)

    def test_bad_response_status_aborts(self):
        mock_post = self.make_mock_post(status='no no NO')
        with main.app.test_client() as test_client:

            response, _ = self.post_simple_assertion(test_client, mock_post)

            self.assertFalse(main.is_logged_in())
            self.assertNotEqual(response.status_code, 200)

    def test_bad_response_ok_aborts(self):
        mock_post = self.make_mock_post(ok=False)
        with main.app.test_client() as test_client:

            response, _ = self.post_simple_assertion(test_client, mock_post)

            self.assertFalse(main.is_logged_in())
            self.assertNotEqual(response.status_code, 200)


class TestLogoutIntegrated(TestWithTestingApp):

    def test_no_content_on_post(self):
        response = self.test_client.post(url_for('logout'))
        self.assertEqual(len(response.data), 0)

    def test_returns_to_front_on_get(self):
        response = self.test_client.get(url_for('logout'))
        self.assert_redirects(response, '/')

    def test_removes_email_and_persona_email_from_session(self):
        with main.app.test_client() as test_client:
            with test_client.session_transaction() as session:
                main.set_logged_in_user('<EMAIL>')
                session['persona_email'] = '<EMAIL>'
            with self.patch_render_template():

                test_client.post('/logout')

            with test_client.session_transaction() as session:
                self.assertFalse(main.is_logged_in())
                self.assertNotIn('persona_email', session)

    def test_no_error_when_email_not_set(self):
        with main.app.test_client() as test_client:
            try:
                with self.patch_render_template():
                    test_client.post('/logout')
            except Exception as e:
                self.fail("exception {} raised for logout "
                          "with no email set".format(repr(e)))


class TestChallengeIntegrated(TestWithDb):

    def test_get_form(self):
        with self.set_user('<EMAIL>') as test_client:
            test_client.get(url_for('challenge'))
        # should not raise

    def test_good_post_creates_game(self):
        assert Game.query.all() == []
        with self.set_user('<EMAIL>') as test_client:
            test_client.post('/challenge', data=dict(
                opponent='<EMAIL>'))
        game = db.session.query(Game).one()
        self.assertEqual(game.white, '<EMAIL>')
        self.assertEqual(game.black, '<EMAIL>')
        self.assertIn("(;", game.sgf)
        self.assertFalse(game.finished)


class TestCreateAccountIntegrated(TestWithDb):

    def test_get_request_shows_form(self):
        with self.patch_render_template() as mock_render:
            self.test_client.get(url_for('create_account'))
            args, kwargs = mock_render.call_args
            self.assertEqual('create_account.html', args[0])

    def test_good_post_creates_account_and_logs_in(self):
        self.assertEqual(db.session.query(User).count(), 0)
        with main.app.test_client() as test_client:
            self.assertFalse(main.is_logged_in())
            with self.patch_render_template():
                test_client.post(url_for('create_account'),
                                 data=dict(username='freddy',
                                           password1='<PASSWORD>',
                                           password2='<PASSWORD>'))
            self.assertTrue(main.is_logged_in())
            self.assertEqual(main.logged_in_user(), 'freddy')
        db.session.rollback()  # to catch missing commits
        user = db.session.query(User).one()
        self.assertEqual(user.username, 'freddy')
        self.assertTrue(user.check_password('<PASSWORD>'))

    def test_non_matching_passwords(self):
        with main.app.test_client() as test_client:
            with self.assert_flashes("do not match"):
                with self.patch_render_template() as mock_render:
                    test_client.post(url_for('create_account'),
                                     data=dict(username='freddy',
                                               password1='<PASSWORD>',
                                               password2='<PASSWORD>'))
                    args, kwargs = mock_render.call_args
                    self.assertEqual('create_account.html', args[0])
            self.assertFalse(main.is_logged_in())


class TestStatusIntegrated(TestWithDb):

    def count_pattern_in(self, pattern, string):
        return len(re.split(pattern, string)) - 1

    def setup_test_games(self):
        self.LOGGED_IN_EMAIL = '<EMAIL>'
        OTHER_EMAIL_1 = '<EMAIL>'
        OTHER_EMAIL_2 = '<EMAIL>'
        game1 = self.add_game(black=self.LOGGED_IN_EMAIL, white=OTHER_EMAIL_1)
        game2 = self.add_game(black=OTHER_EMAIL_1, white=OTHER_EMAIL_2)
        game3 = self.add_game(black=OTHER_EMAIL_1, white=self.LOGGED_IN_EMAIL)
        game4 = self.add_game(black=OTHER_EMAIL_1, white=self.LOGGED_IN_EMAIL,
                              sgf="(;B[jj])")
        game5 = self.add_game(black=OTHER_EMAIL_1, white=self.LOGGED_IN_EMAIL,
                              sgf="(;B[])")
        game6 = self.add_game(black=self.LOGGED_IN_EMAIL, white=OTHER_EMAIL_1,
                              finished=True)
        return (game1, game2, game3, game4, game5, game6,)

    def test_sends_games_to_correct_template_params(self):
        game1, game2, game3, game4, game5, game6 = self.setup_test_games()
        with self.set_user() as test_client:
            with self.patch_render_template() as mock_render:

                test_client.get(url_for('status'))

                args, kwargs = mock_render.call_args
        self.assertEqual(args[0], "status.html")
        your_turn_games = kwargs['your_turn_games']
        not_your_turn_games = kwargs['not_your_turn_games']

        self.assertEqual(set(your_turn_games), set([game1, game4, game5]))
        self.assertEqual(set(not_your_turn_games), set([game3]))

    def test_shows_links_to_existing_games(self):
        self.setup_test_games()
        with self.set_user() as test_client:
            response = test_client.get(url_for('status'))
        self.assertEqual(
                self.count_pattern_in(r"Game \d", str(response.get_data())),
                4)

    def test_anonymous_users_redirected_to_front(self):
        with main.app.test_client() as test_client:
            response = test_client.get(url_for('status'))
        self.assert_redirects(response, '/')

    def test_games_come_out_sorted(self):
        """Regression test: going via dictionaries can break sorting"""
        for i in range(5):
            self.add_game(black='<EMAIL>', white='<EMAIL>')
            self.add_game(black='<EMAIL>', white='<EMAIL>')
        with self.set_user('<EMAIL>') as test_client:
            with self.patch_render_template() as mock_render:

                test_client.get(url_for('status'))

                args, kwargs = mock_render.call_args
        your_turn_games = kwargs['your_turn_games']
        not_your_turn_games = kwargs['not_your_turn_games']

        def game_key(game):
            return game.id
        self.assertEqual(
                your_turn_games,
                sorted(your_turn_games, key=game_key))
        self.assertEqual(
                not_your_turn_games,
                sorted(not_your_turn_games, key=game_key))


class TestFinishedIntegrated(TestWithDb):

    def test_anonymous_users_redirected_to_front(self):
        with main.app.test_client() as test_client:
            response = test_client.get(url_for('finished'))
        self.assert_redirects(response, '/')

    def test_shows_only_finished_games(self):
        black_game = self.add_game(black='<EMAIL>', finished=True)
        white_game = self.add_game(white='<EMAIL>', finished=True)
        self.add_game(black='<EMAIL>', finished=False)
        self.add_game(finished=True)
        with self.set_user('<EMAIL>') as test_client:
            with self.patch_render_template() as mock_render:

                test_client.get(url_for('finished'))

                args, kwargs = mock_render.call_args
        self.assertEqual(args[0], "finished.html")
        finished_games = kwargs['finished_games']
        self.assertEqual(set(finished_games), set([black_game, white_game]))


class TestGameIntegrated(TestWithDb):

    def test_404_if_no_game_specified(self):
        response = self.test_client.get('/game')
        self.assert404(response)

    def test_redirects_to_home_if_game_not_found(self):
        out_of_range = max(chain([0], Game.query.filter(Game.id))) + 1
        with main.app.test_client() as test_client:
            response = test_client.get(url_for('game', game_no=out_of_range))
        self.assert_redirects(response, '/')

    def do_mocked_get(self, game):
        with self.set_user('<EMAIL>') as test_client:
            with self.patch_render_template() as mock_render:
                test_client.get(url_for('game', game_no=game.id))
                return mock_render.call_args

    def test_passes_sgf_in_form(self):
        game = self.add_game(['.b'])
        args, kwargs = self.do_mocked_get(game)
        self.assertIn("B[ba]", kwargs['form'].data.data)

    def test_after_two_passes_activates_scoring_interface(self):
        game = self.add_game("(;B[];W[])")
        args, kwargs = self.do_mocked_get(game)
        self.assertEqual(kwargs['with_scoring'], True)


class TestResignIntegrated(TestWithDb):

    def test_sets_finished(self):
        game = self.add_game()
        game_no = game.id
        self.assertFalse(game.finished,
                         "game should not initially be finished")
        with self.set_user(game.black) as test_client:
            test_client.post(url_for('play', game_no=game.id),
                             data=dict(resign_button='resign'))
        db.session.rollback()  # to catch missing commits
        game = db.session.query(Game).filter_by(id=game_no).one()
        self.assertTrue(game.finished,
                        "game should be finished after resign posted")

    def test_nothing_happens_off_turn(self):
        game = self.add_game()
        self.assertFalse(game.finished,
                         "game should not initially be finished")
        with self.set_user(game.white) as test_client:
            test_client.post(url_for('play', game_no=game.id),
                             data=dict(resign_button='resign'))
        self.assertFalse(game.finished,
                         "game should not be finished")


class TestPlayIntegrated(TestWithDb):

    def test_can_add_stones_and_passes_to_two_games(self):
        game1 = self.add_game()
        game2 = self.add_game()
        with self.patch_render_template():
            with self.set_user('<EMAIL>') as test_client:
                test_client.post(url_for('play', game_no=game1.id),
                                 data=dict(response="(;B[pd])"))
{'fraction_non_alphanumeric': 0.10869865855345043, 'fraction_numerical': 0.003650947310192228, 'mean_word_length': 2.3474678270530505, 'pattern_counts': {'":': 0, '<': 77, '<?xml version=': 0, '>': 77, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 50, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6153955', 'n_tokens_mistral': 10842, 'n_tokens_neox': 10478, 'n_words': 1822}