<commit_before>from datetime import datetime, timezone
from enum import Enum, IntEnum, unique
from json import dumps as json_dumps
from json import loads as json_loads
from typing import Dict, List

from attr import define
from bson import dumps as bson_dumps
from bson import loads as bson_loads
from hypothesis import given
from hypothesis.strategies import (
    binary,
    characters,
    composite,
    datetimes,
    dictionaries,
    floats,
    frozensets,
    integers,
    just,
    lists,
    sets,
    text,
)
from msgpack import dumps as msgpack_dumps
from msgpack import loads as msgpack_loads
from orjson import dumps as orjson_dumps
from orjson import loads as orjson_loads
from tomlkit import dumps as tomlkit_dumps
from tomlkit import loads as tomlkit_loads
from ujson import dumps as ujson_dumps
from ujson import loads as ujson_loads
from yaml import safe_dump, safe_load

from cattr._compat import (
    Counter,
    FrozenSet,
    Mapping,
    MutableMapping,
    MutableSequence,
    MutableSet,
    Sequence,
    Set,
    TupleSubscriptable,
)
from cattr.preconf.bson import make_converter as bson_make_converter
from cattr.preconf.json import make_converter as json_make_converter
from cattr.preconf.msgpack import make_converter as msgpack_make_converter
from cattr.preconf.orjson import make_converter as orjson_make_converter
from cattr.preconf.pyyaml import make_converter as pyyaml_make_converter
from cattr.preconf.tomlkit import make_converter as tomlkit_make_converter
from cattr.preconf.ujson import make_converter as ujson_make_converter

@define
class Everything:
    @unique
    class AnIntEnum(IntEnum):
        A = 1

    @unique
    class AStringEnum(str, Enum):
        A = "a"

    string: str
    bytes: bytes
    an_int: int
    a_float: float
    a_dict: Dict[str, int]
    a_list: List[int]
    a_homogenous_tuple: TupleSubscriptable[int, ...]
    a_hetero_tuple: TupleSubscriptable[str, int, float]
    a_counter: Counter[str]
    a_mapping: Mapping[int, float]
    a_mutable_mapping: MutableMapping[float, str]
    a_sequence: Sequence[float]
    a_mutable_sequence: MutableSequence[str]
    a_set: Set[float]
    a_mutable_set: MutableSet[int]
    a_frozenset: FrozenSet[str]
    an_int_enum: AnIntEnum
    a_str_enum: AStringEnum
    a_datetime: datetime

@composite
def everythings(
    draw,
    min_int=None,
    max_int=None,
    allow_inf=True,
    allow_null_bytes_in_keys=True,
    allow_quotes_in_keys=True,
    allow_control_characters_in_values=True,
    min_key_length=0,
    allow_datetime_microseconds=True,
):
    key_text = text(
        characters(
            blacklist_categories=("Cs",)
            if allow_null_bytes_in_keys
            else ("Cs", "Cc"),
            blacklist_characters='"' if not allow_quotes_in_keys else None,
        ),
        min_size=min_key_length,
    )
    strings = text(
        characters(
            blacklist_categories=("Cs",)
            if allow_control_characters_in_values
            else ("Cs", "Cc")
        ),
    )
    dts = datetimes(
        min_value=datetime(1900, 1, 1),
        max_value=datetime(2200, 1, 1),
        timezones=just(timezone.utc),
    )
    if not allow_datetime_microseconds:
        dts = dts.map(
            lambda d: datetime(
                d.year,
                d.month,
                d.day,
                d.hour,
                d.minute,
                d.second,
                tzinfo=d.tzinfo,
            )
        )
    return Everything(
        draw(strings),
        draw(binary()),
        draw(integers(min_value=min_int, max_value=max_int)),
        draw(floats(allow_nan=False, allow_infinity=allow_inf)),
        draw(
            dictionaries(
                key_text, integers(min_value=min_int, max_value=max_int)
            )
        ),
        draw(lists(integers(min_value=min_int, max_value=max_int))),
        tuple(draw(lists(integers(min_value=min_int, max_value=max_int)))),
        (
            draw(strings),
            draw(integers(min_value=min_int, max_value=max_int)),
            draw(floats(allow_nan=False, allow_infinity=allow_inf)),
        ),
        Counter(
            draw(
                dictionaries(
                    key_text, integers(min_value=min_int, max_value=max_int)
                )
            )
        ),
        draw(
            dictionaries(
                integers(min_value=min_int, max_value=max_int),
                floats(allow_nan=False, allow_infinity=allow_inf),
            )
        ),
        draw(
            dictionaries(
                floats(allow_nan=False, allow_infinity=allow_inf), strings
            )
        ),
        draw(lists(floats(allow_nan=False, allow_infinity=allow_inf))),
        draw(lists(strings)),
        draw(sets(floats(allow_nan=False, allow_infinity=allow_inf))),
        draw(sets(integers(min_value=min_int, max_value=max_int))),
        draw(frozensets(strings)),
        Everything.AnIntEnum.A,
        Everything.AStringEnum.A,
        draw(dts),
    )

@given(everythings())
def test_stdlib_json(everything: Everything):
    converter = json_make_converter()
    assert (
        converter.structure(
            json_loads(json_dumps(converter.unstructure(everything))),
            Everything,
        )
        == everything
    )

@given(
    everythings(
        min_int=-9223372036854775808,
        max_int=9223372036854775807,
        allow_inf=False,
    )
)
def test_ujson(everything: Everything):
    converter = ujson_make_converter()
    raw = ujson_dumps(converter.unstructure(everything))
    assert (
        converter.structure(
            ujson_loads(raw),
            Everything,
        )
        == everything
    )

@given(
    everythings(
        min_int=-9223372036854775808,
        max_int=9223372036854775807,
        allow_inf=False,
    )
)
def test_orjson(everything: Everything):
    converter = orjson_make_converter()
    raw = orjson_dumps(converter.unstructure(everything))
    assert (
        converter.structure(
            orjson_loads(raw),
            Everything,
        )
        == everything
    )

@given(everythings(min_int=-9223372036854775808, max_int=18446744073709551615))
def test_msgpack(everything: Everything):
    converter = msgpack_make_converter()
    raw = msgpack_dumps(converter.unstructure(everything))
    assert (
        converter.structure(
            msgpack_loads(raw, strict_map_key=False),
            Everything,
        )
        == everything
    )

@given(
    everythings(
        min_int=-9223372036854775808,
        max_int=18446744073709551615,
        allow_null_bytes_in_keys=False,
        allow_datetime_microseconds=False,
    )
)
def test_bson(everything: Everything):
    converter = bson_make_converter()
    raw = bson_dumps(converter.unstructure(everything))
    assert (
        converter.structure(
            bson_loads(raw),
            Everything,
        )
        == everything
    )

@given(everythings())
def test_pyyaml(everything: Everything):
    converter = pyyaml_make_converter()
    unstructured = converter.unstructure(everything)
    raw = safe_dump(unstructured)
    assert (
        converter.structure(
            safe_load(raw),
            Everything,
        )
        == everything
    )

@given(
    everythings(
        min_key_length=1,
        allow_null_bytes_in_keys=False,
        allow_quotes_in_keys=False,
        allow_control_characters_in_values=False,
    )
)
def test_tomlkit(everything: Everything):
    converter = tomlkit_make_converter()
    unstructured = converter.unstructure(everything)
    raw = tomlkit_dumps(unstructured)
    assert (
        converter.structure(
            tomlkit_loads(raw),
            Everything,
        )
        == everything
    )
<commit_msg>test_preconf: Support deselecting tests with extra deps<commit_after>from datetime import datetime, timezone
from enum import Enum, IntEnum, unique
from json import dumps as json_dumps
from json import loads as json_loads
from typing import Dict, List

from attr import define
from hypothesis import given
from hypothesis.strategies import (
    binary,
    characters,
    composite,
    datetimes,
    dictionaries,
    floats,
    frozensets,
    integers,
    just,
    lists,
    sets,
    text,
)

from cattr._compat import (
    Counter,
    FrozenSet,
    Mapping,
    MutableMapping,
    MutableSequence,
    MutableSet,
    Sequence,
    Set,
    TupleSubscriptable,
)
from cattr.preconf.bson import make_converter as bson_make_converter
from cattr.preconf.json import make_converter as json_make_converter
from cattr.preconf.msgpack import make_converter as msgpack_make_converter
from cattr.preconf.orjson import make_converter as orjson_make_converter
from cattr.preconf.pyyaml import make_converter as pyyaml_make_converter
from cattr.preconf.tomlkit import make_converter as tomlkit_make_converter
from cattr.preconf.ujson import make_converter as ujson_make_converter

@define
class Everything:
    @unique
    class AnIntEnum(IntEnum):
        A = 1

    @unique
    class AStringEnum(str, Enum):
        A = "a"

    string: str
    bytes: bytes
    an_int: int
    a_float: float
    a_dict: Dict[str, int]
    a_list: List[int]
    a_homogenous_tuple: TupleSubscriptable[int, ...]
    a_hetero_tuple: TupleSubscriptable[str, int, float]
    a_counter: Counter[str]
    a_mapping: Mapping[int, float]
    a_mutable_mapping: MutableMapping[float, str]
    a_sequence: Sequence[float]
    a_mutable_sequence: MutableSequence[str]
    a_set: Set[float]
    a_mutable_set: MutableSet[int]
    a_frozenset: FrozenSet[str]
    an_int_enum: AnIntEnum
    a_str_enum: AStringEnum
    a_datetime: datetime

@composite
def everythings(
    draw,
    min_int=None,
    max_int=None,
    allow_inf=True,
    allow_null_bytes_in_keys=True,
    allow_quotes_in_keys=True,
    allow_control_characters_in_values=True,
    min_key_length=0,
    allow_datetime_microseconds=True,
):
    key_text = text(
        characters(
            blacklist_categories=("Cs",)
            if allow_null_bytes_in_keys
            else ("Cs", "Cc"),
            blacklist_characters='"' if not allow_quotes_in_keys else None,
        ),
        min_size=min_key_length,
    )
    strings = text(
        characters(
            blacklist_categories=("Cs",)
            if allow_control_characters_in_values
            else ("Cs", "Cc")
        ),
    )
    dts = datetimes(
        min_value=datetime(1900, 1, 1),
        max_value=datetime(2200, 1, 1),
        timezones=just(timezone.utc),
    )
    if not allow_datetime_microseconds:
        dts = dts.map(
            lambda d: datetime(
                d.year,
                d.month,
                d.day,
                d.hour,
                d.minute,
                d.second,
                tzinfo=d.tzinfo,
            )
        )
    return Everything(
        draw(strings),
        draw(binary()),
        draw(integers(min_value=min_int, max_value=max_int)),
        draw(floats(allow_nan=False, allow_infinity=allow_inf)),
        draw(
            dictionaries(
                key_text, integers(min_value=min_int, max_value=max_int)
            )
        ),
        draw(lists(integers(min_value=min_int, max_value=max_int))),
        tuple(draw(lists(integers(min_value=min_int, max_value=max_int)))),
        (
            draw(strings),
            draw(integers(min_value=min_int, max_value=max_int)),
            draw(floats(allow_nan=False, allow_infinity=allow_inf)),
        ),
        Counter(
            draw(
                dictionaries(
                    key_text, integers(min_value=min_int, max_value=max_int)
                )
            )
        ),
        draw(
            dictionaries(
                integers(min_value=min_int, max_value=max_int),
                floats(allow_nan=False, allow_infinity=allow_inf),
            )
        ),
        draw(
            dictionaries(
                floats(allow_nan=False, allow_infinity=allow_inf), strings
            )
        ),
        draw(lists(floats(allow_nan=False, allow_infinity=allow_inf))),
        draw(lists(strings)),
        draw(sets(floats(allow_nan=False, allow_infinity=allow_inf))),
        draw(sets(integers(min_value=min_int, max_value=max_int))),
        draw(frozensets(strings)),
        Everything.AnIntEnum.A,
        Everything.AStringEnum.A,
        draw(dts),
    )

@given(everythings())
def test_stdlib_json(everything: Everything):
    converter = json_make_converter()
    assert (
        converter.structure(
            json_loads(json_dumps(converter.unstructure(everything))),
            Everything,
        )
        == everything
    )

@given(
    everythings(
        min_int=-9223372036854775808,
        max_int=9223372036854775807,
        allow_inf=False,
    )
)
def test_ujson(everything: Everything):
    from ujson import dumps as ujson_dumps
    from ujson import loads as ujson_loads
    converter = ujson_make_converter()
    raw = ujson_dumps(converter.unstructure(everything))
    assert (
        converter.structure(
            ujson_loads(raw),
            Everything,
        )
        == everything
    )

@given(
    everythings(
        min_int=-9223372036854775808,
        max_int=9223372036854775807,
        allow_inf=False,
    )
)
def test_orjson(everything: Everything):
    from orjson import dumps as orjson_dumps
    from orjson import loads as orjson_loads
    converter = orjson_make_converter()
    raw = orjson_dumps(converter.unstructure(everything))
    assert (
        converter.structure(
            orjson_loads(raw),
            Everything,
        )
        == everything
    )

@given(everythings(min_int=-9223372036854775808, max_int=18446744073709551615))
def test_msgpack(everything: Everything):
    from msgpack import dumps as msgpack_dumps
    from msgpack import loads as msgpack_loads
    converter = msgpack_make_converter()
    raw = msgpack_dumps(converter.unstructure(everything))
    assert (
        converter.structure(
            msgpack_loads(raw, strict_map_key=False),
            Everything,
        )
        == everything
    )

@given(
    everythings(
        min_int=-9223372036854775808,
        max_int=18446744073709551615,
        allow_null_bytes_in_keys=False,
        allow_datetime_microseconds=False,
    )
)
def test_bson(everything: Everything):
    from bson import dumps as bson_dumps
    from bson import loads as bson_loads
    converter = bson_make_converter()
    raw = bson_dumps(converter.unstructure(everything))
    assert (
        converter.structure(
            bson_loads(raw),
            Everything,
        )
        == everything
    )

@given(everythings())
def test_pyyaml(everything: Everything):
    from yaml import safe_dump, safe_load
    converter = pyyaml_make_converter()
    unstructured = converter.unstructure(everything)
    raw = safe_dump(unstructured)
    assert (
        converter.structure(
            safe_load(raw),
            Everything,
        )
        == everything
    )

@given(
    everythings(
        min_key_length=1,
        allow_null_bytes_in_keys=False,
        allow_quotes_in_keys=False,
        allow_control_characters_in_values=False,
    )
)
def test_tomlkit(everything: Everything):
    from tomlkit import dumps as tomlkit_dumps
    from tomlkit import loads as tomlkit_loads
    converter = tomlkit_make_converter()
    unstructured = converter.unstructure(everything)
    raw = tomlkit_dumps(unstructured)
    assert (
        converter.structure(
            tomlkit_loads(raw),
            Everything,
        )
        == everything
    )
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
test_pycrawl
----------------------------------

Tests for `pycrawl` module.
"""

from contextlib import contextmanager
import errno
import os
import re
import shutil
import time
import unittest
try:  # Python 3
    from urllib.parse import urlparse
except:  # Python 2
    from urlparse import urlparse

import bs4

from tests.run_server import run_server, stop_server
from pycrawl import pycrawl

class TestPycrawl(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        cls.server = run_server()
        time.sleep(0.5)  # give it time to start up

    @classmethod
    def tearDownClass(cls):
        stop_server(cls.server)

    def setUp(self):
        pass

    def tearDown(self):
        pass

    @contextmanager
    def run_main_with_url(self, url):
        argv = ['pycrawl.py', url]
        try:
            pycrawl.main(argv)
            yield
        finally:
            try:
                basename = urlparse(url).hostname
                shutil.rmtree(basename)
            except OSError as e:
                if e.errno == errno.ENOENT:
                    pass
                else:
                    raise

    def test_nonexistent_url(self):
        with self.run_main_with_url('http://nonexistentsite.nes/badpath'):
            pass  # does not raise

    def test_non_html_url(self):
        with self.run_main_with_url(
                'http://localhost:8000/Python_logo_100x100.jpg'):
            self.assertTrue(
                os.path.isfile('localhost/Python_logo_100x100.jpg'))

    def test_valid_url_creates_dir_and_file(self):
        with self.run_main_with_url('http://localhost:8000'):
            with open('localhost/__root__') as f:
                document = bs4.BeautifulSoup(f)
        self.assertTrue(bool(document.find(text=re.compile("Text"))))

if __name__ == '__main__':
    unittest.main()
<commit_msg>some test cleanup<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
test_pycrawl
----------------------------------

Tests for `pycrawl` module.
"""

import errno
from functools import wraps
import os
import re
import shutil
import time
import unittest
try:  # Python 3
    from urllib.parse import urlparse
except:  # Python 2
    from urlparse import urlparse

import bs4

from tests.run_server import run_server, stop_server
from pycrawl import pycrawl

def run_main_with_url(url):
    """Run main on the given URL, then delete the downloaded files after."""
    def decorator(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            argv = ['pycrawl.py', url]
            try:
                pycrawl.main(argv)
                f(*args, **kwargs)
            finally:
                # remove created download dir
                try:
                    basename = urlparse(url).hostname
                    shutil.rmtree(basename)
                except OSError as e:
                    if e.errno == errno.ENOENT:
                        pass
                    else:
                        raise
        return wrapper
    return decorator

class TestPycrawl(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        cls.server = run_server()
        time.sleep(0.5)  # give it time to start up

    @classmethod
    def tearDownClass(cls):
        stop_server(cls.server)

    def setUp(self):
        pass

    def tearDown(self):
        pass

    @run_main_with_url('http://nonexistentsite.nes/badpath')
    def test_nonexistent_url(self):
        self.assertFalse(
            os.path.isfile('nonexistentsite.nes/badpath'))

    @run_main_with_url('http://localhost:8000/Python_logo_100x100.jpg')
    def test_non_html_url(self):
        self.assertTrue(os.path.isfile('localhost/Python_logo_100x100.jpg'))

    @run_main_with_url('http://localhost:8000')
    def test_valid_url_creates_dir_and_file(self):
        with open('localhost/__root__') as f:
            document = bs4.BeautifulSoup(f)
        self.assertTrue(bool(document.find(text=re.compile("Text"))))

if __name__ == '__main__':
    unittest.main()
<|endoftext|>


<commit_before>import os
import random
import re

import pytest
from flask.testing import FlaskClient
from flask import session

os.environ['PYDRILL_CONFIG'] = os.path.join(os.path.dirname(__file__), 'pydrill.cfg')
from pydrill import app, db, redis_store
from pydrill import models
from pydrill.jinja_env import get_score_text
from pydrill.utils import User, TEAM_APPLE, TEAM_HN, TEAM_LINUX

EASY_Q = 'average'
MEDIUM_Q = 'static-decorator'
HARD_Q = 'assign-to-empty-list'

MAC_USER_AGENT = ('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 '
                  '(KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36')

LINUX_USER_AGENT = ('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 '
                    '(KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36')

MAC_USER_WITH_BAD_REFERER = {'HTTP_USER_AGENT': MAC_USER_AGENT,
                             'HTTP_REFERER': 'parse this'}

LINUX_USER_WITH_HN_REFERER = {'HTTP_USER_AGENT': LINUX_USER_AGENT,
                              'HTTP_REFERER': 'https://news.ycombinator.com/item?id=test'}

MAC_USER = {'HTTP_USER_AGENT': MAC_USER_AGENT}

# TODO: switch to app.test_client when Flask 1.0 is ready
def new_test_client(environ_base, *args, **kwargs):
    """Copy-pasted from Flask.test_client because we need to pass environ_base in .get() and .post()
    which test_client can do only from version 1.0 which is not production ready yet.
    """
    return Client(environ_base, app, app.response_class, *args, **kwargs)

class Client(FlaskClient):
    def __init__(self, environ_base, *args, **kwargs):
        self.__environ_base = environ_base
        super(Client, self).__init__(*args, **kwargs)

    def get(self, *args, **kwargs):
        return super(Client, self).get(*args, environ_base=self.__environ_base, **kwargs)

    def checked_get(self, url):
        rv = self.get(url)
        assert rv.status_code == 200
        return rv

    def post(self, *args, **kwargs):
        return super(Client, self).post(*args, environ_base=self.__environ_base, **kwargs)

    def checked_post(self, url):
        rv = self.post(url)
        assert rv.status_code == 302
        return rv

    def ask_me(self, question_id):
        url = '/ask/{}/100/'.format(question_id)
        return self.checked_get(url)

    def explain_to_me(self, question_id):
        url = '/explain/{}/1/100/'.format(question_id)
        return self.checked_get(url)

    def answer(self, question_id, is_correct):
        self.ask_me(question_id)
        question = models.Question.query.get(question_id)
        url = '/answer/{}/{:d}/100/'.format(question_id, get_answer(question, is_correct).id)
        return self.checked_post(url)

    def answer_correct(self, question_id):
        return self.answer(question_id, is_correct=True)

    def answer_wrong(self, question_id):
        return self.answer(question_id, is_correct=False)

@pytest.fixture(autouse=True)
def flush_redis_db():
    redis_store.flushdb()

@pytest.fixture(autouse=True, scope='session')
def create_sql_db():
    db.drop_all()
    db.create_all()
    questions_dir = os.path.join(os.path.dirname(__file__), 'questions')
    models.load_questions(questions_dir)

@pytest.fixture(autouse=True)
def run_app_in_testing_mode():
    app.config['TESTING'] = True

@pytest.fixture()
def steve():
    return new_test_client(MAC_USER_WITH_BAD_REFERER)

@pytest.fixture()
def paul():
    return new_test_client(LINUX_USER_WITH_HN_REFERER)

@pytest.fixture()
def tim():
    return new_test_client(MAC_USER)

def get_user():
    return User(**session['user'])

def test_user_id(paul):
    with paul:
        paul.ask_me(EASY_Q)
        user = get_user()
        assert len(user.id) == 36  # length of str(uuid4) is 36
        paul.ask_me(EASY_Q)
        # id doesn't change after the first visit
        assert get_user().id == user.id

def test_new_user_score(paul):
    with paul:
        paul.ask_me(EASY_Q)
        assert get_user().score == 0

def test_user_teams(paul):
    with paul:
        paul.ask_me(EASY_Q)
        assert_same_items(get_user().teams, [TEAM_LINUX, TEAM_HN])

def test_questions():
    assert models.Question.query.count() == 3

@pytest.mark.parametrize('question_id, are_correct, scores', [
    (EASY_Q, [True, True], [1, 1]),
    (EASY_Q, [False, True], [0, 0]),
])
def test_only_first_answer_can_increase_score(steve, question_id, are_correct, scores):
    assert len(are_correct) == len(scores)
    for is_correct, score in zip(are_correct, scores):
        steve.answer(question_id, is_correct=is_correct)
        assert_team_score(TEAM_APPLE, score_sum=score)

def matches_any_ask_url(*question_ids):
    parts = [r'/ask/{}/(\d+)/$'.format(q) for q in question_ids]
    return '|'.join(parts)

# TODO: test it separate tests with good naming maybe?
@pytest.mark.parametrize('question_ids, redirect_path_re', [
    ([EASY_Q], matches_any_ask_url(MEDIUM_Q, HARD_Q)),
    ([EASY_Q, MEDIUM_Q], matches_any_ask_url(HARD_Q)),
    ([EASY_Q, MEDIUM_Q, HARD_Q], matches_any_ask_url('.*'))
])
def test_answer_redirects(steve, question_ids, redirect_path_re):
    for i, question_id in enumerate(question_ids):
        rv = steve.answer(question_id, is_correct=random.choice([True, False]))
        if i == len(question_ids) - 1:
            # TODO: check that absolute url is correct
            assert re.search(redirect_path_re, rv.location)

def assert_same_items(xs, ys):
    assert sorted(xs) == sorted(ys)

def get_answer(question, is_correct):
    return question.answers.filter_by(is_correct=is_correct).first()

def get_correct_answer(question):
    return get_answer(question, is_correct=True)

def test_ask_without_seed(paul):
    # TODO: factor out with app.new_test_client, subclass it,
    # TODO: pass user (e.g PAUL) to its __init__ method and handle seeds etc
    rv = paul.get('/ask/{}/'.format(EASY_Q))
    assert rv.status_code == 302
    assert re.search(matches_any_ask_url(EASY_Q), rv.location)

def test_team_scores(steve, paul, tim):
    steve.answer_correct(EASY_Q)
    assert_team_score(TEAM_APPLE, num_users=1, score_sum=1)

    tim.answer_wrong(EASY_Q)
    assert_team_score(TEAM_APPLE, num_users=2, score_sum=1)

    paul.answer_correct(EASY_Q)
    assert_team_score(TEAM_APPLE, num_users=2, score_sum=1)  # paul is not in Apple team
    assert_team_score(TEAM_LINUX, num_users=1, score_sum=1)
    assert_team_score(TEAM_HN, num_users=1, score_sum=1)

    steve.answer_correct(MEDIUM_Q)
    assert_team_score(TEAM_APPLE, num_users=2, score_sum=3)

def assert_team_score(team, **expected):
    score = {k: int(v) for k, v in redis_store.hgetall('team:{}'.format(team)).viewitems()}
    for key, value in expected.viewitems():
        assert score[key] == value

# execute this test 10 times to thoroughly check random behaviour
@pytest.mark.parametrize('i', range(10))
def test_never_ask_the_same_question_twice_in_a_row(steve, i):
    # we need to answer every question, because otherwise
    # answer(steve, EASY_Q, ...) will always redirect to
    # the unanswered question.
    # We want to test that even if every question is answered,
    # then we don't ask the same question twice in row anyway.
    for question in models.Question.query.all():
        steve.answer_correct(question.id)

    rv = steve.answer_correct(EASY_Q)
    # TODO: check that absolute url is correct
    assert re.search(matches_any_ask_url(EASY_Q), rv.location) is None

@pytest.mark.parametrize('rank, num_users, expected_text', [
    (1, 1, 'top 1%'),
    (1, 2, 'top 1%'),
    (2, 2, 'bottom 50%'),
    (1, 3, 'top 1%'),
    (2, 3, 'top 50%'),
    (3, 3, 'bottom 33%'),
])
def test_get_score_text(rank, num_users, expected_text):
    assert get_score_text(rank, num_users) == expected_text

def test_ask_question_rendering(steve):
    rv = steve.ask_me(EASY_Q)
    # checking that XXX / 2 is highlighted
    assert '/ 2' in rv.data

def test_explain_question_rendering(steve):
    rv = steve.explain_to_me(EASY_Q)
    assert '__future__' in rv.data

def test_score_rendering(steve):
    steve.answer_correct(EASY_Q)  # so scores aren't empty
    rv = steve.checked_get('/score/')
    assert_has_score(rv, 1)
    assert '{} is your team'.format(TEAM_APPLE) in rv.data

def test_score_top_text(steve, paul):
    steve.answer_correct(EASY_Q)
    rv = steve.checked_get('/score/')
    assert "You're in the top 1%" in rv.data

    paul.answer_correct(MEDIUM_Q)
    rv = paul.checked_get('/score/')
    assert "You're in the top 1%" in rv.data

    rv = steve.checked_get('/score/')
    assert "You're in the bottom 50%" in rv.data

def test_score_during_ask(steve):
    rv = steve.ask_me(EASY_Q)
    assert_has_score(rv, 0)

# TODO: don't test markup with string comparisons, use css selectors
def assert_has_score(rv, expected_score):
    assert 'Score: {:d}'.format(expected_score) in rv.data
<commit_msg>Add make_path helper that builds url paths with random seed<commit_after>import os
import random
import re

import pytest
from flask.testing import FlaskClient
from flask import session

os.environ['PYDRILL_CONFIG'] = os.path.join(os.path.dirname(__file__), 'pydrill.cfg')
from pydrill import app, db, redis_store
from pydrill import models
from pydrill.jinja_env import get_score_text
from pydrill.utils import User, TEAM_APPLE, TEAM_HN, TEAM_LINUX

EASY_Q = 'average'
MEDIUM_Q = 'static-decorator'
HARD_Q = 'assign-to-empty-list'

MAC_USER_AGENT = ('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 '
                  '(KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36')

LINUX_USER_AGENT = ('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 '
                    '(KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36')

MAC_USER_WITH_BAD_REFERER = {'HTTP_USER_AGENT': MAC_USER_AGENT,
                             'HTTP_REFERER': 'parse this'}

LINUX_USER_WITH_HN_REFERER = {'HTTP_USER_AGENT': LINUX_USER_AGENT,
                              'HTTP_REFERER': 'https://news.ycombinator.com/item?id=test'}

MAC_USER = {'HTTP_USER_AGENT': MAC_USER_AGENT}

# TODO: switch to app.test_client when Flask 1.0 is ready
def new_test_client(environ_base, *args, **kwargs):
    """Copy-pasted from Flask.test_client because we need to pass environ_base in .get() and .post()
    which test_client can do only from version 1.0 which is not production ready yet.
    """
    return Client(environ_base, app, app.response_class, *args, **kwargs)

class Client(FlaskClient):
    def __init__(self, environ_base, *args, **kwargs):
        self.__environ_base = environ_base
        super(Client, self).__init__(*args, **kwargs)

    def get(self, *args, **kwargs):
        return super(Client, self).get(*args, environ_base=self.__environ_base, **kwargs)

    def checked_get(self, url):
        rv = self.get(url)
        assert rv.status_code == 200
        return rv

    def post(self, *args, **kwargs):
        return super(Client, self).post(*args, environ_base=self.__environ_base, **kwargs)

    def checked_post(self, url):
        rv = self.post(url)
        assert rv.status_code == 302
        return rv

    def ask_me(self, question_id):
        url = make_path('ask', question_id)
        return self.checked_get(url)

    def explain_to_me(self, question_id):
        url = make_path('explain', question_id, 1)
        return self.checked_get(url)

    def answer(self, question_id, is_correct):
        self.ask_me(question_id)
        question = models.Question.query.get(question_id)
        url = make_path('answer', question_id, get_answer(question, is_correct).id)
        return self.checked_post(url)

    def answer_correct(self, question_id):
        return self.answer(question_id, is_correct=True)

    def answer_wrong(self, question_id):
        return self.answer(question_id, is_correct=False)

def make_path(*path_parts):
    seed = str(random.randint(1, 100))
    return '/'.join([''] + map(str, path_parts) + [seed, ''])

@pytest.fixture(autouse=True)
def flush_redis_db():
    redis_store.flushdb()

@pytest.fixture(autouse=True, scope='session')
def create_sql_db():
    db.drop_all()
    db.create_all()
    questions_dir = os.path.join(os.path.dirname(__file__), 'questions')
    models.load_questions(questions_dir)

@pytest.fixture(autouse=True)
def run_app_in_testing_mode():
    app.config['TESTING'] = True

@pytest.fixture()
def steve():
    return new_test_client(MAC_USER_WITH_BAD_REFERER)

@pytest.fixture()
def paul():
    return new_test_client(LINUX_USER_WITH_HN_REFERER)

@pytest.fixture()
def tim():
    return new_test_client(MAC_USER)

def get_user():
    return User(**session['user'])

def test_user_id(paul):
    with paul:
        paul.ask_me(EASY_Q)
        user = get_user()
        assert len(user.id) == 36  # length of str(uuid4) is 36
        paul.ask_me(EASY_Q)
        # id doesn't change after the first visit
        assert get_user().id == user.id

def test_new_user_score(paul):
    with paul:
        paul.ask_me(EASY_Q)
        assert get_user().score == 0

def test_user_teams(paul):
    with paul:
        paul.ask_me(EASY_Q)
        assert_same_items(get_user().teams, [TEAM_LINUX, TEAM_HN])

def test_questions():
    assert models.Question.query.count() == 3

@pytest.mark.parametrize('question_id, are_correct, scores', [
    (EASY_Q, [True, True], [1, 1]),
    (EASY_Q, [False, True], [0, 0]),
])
def test_only_first_answer_can_increase_score(steve, question_id, are_correct, scores):
    assert len(are_correct) == len(scores)
    for is_correct, score in zip(are_correct, scores):
        steve.answer(question_id, is_correct=is_correct)
        assert_team_score(TEAM_APPLE, score_sum=score)

def matches_any_ask_url(*question_ids):
    parts = [r'/ask/{}/(\d+)/$'.format(q) for q in question_ids]
    return '|'.join(parts)

# TODO: test it separate tests with good naming maybe?
@pytest.mark.parametrize('question_ids, redirect_path_re', [
    ([EASY_Q], matches_any_ask_url(MEDIUM_Q, HARD_Q)),
    ([EASY_Q, MEDIUM_Q], matches_any_ask_url(HARD_Q)),
    ([EASY_Q, MEDIUM_Q, HARD_Q], matches_any_ask_url('.*'))
])
def test_answer_redirects(steve, question_ids, redirect_path_re):
    for i, question_id in enumerate(question_ids):
        rv = steve.answer(question_id, is_correct=random.choice([True, False]))
        if i == len(question_ids) - 1:
            # TODO: check that absolute url is correct
            assert re.search(redirect_path_re, rv.location)

def assert_same_items(xs, ys):
    assert sorted(xs) == sorted(ys)

def get_answer(question, is_correct):
    return question.answers.filter_by(is_correct=is_correct).first()

def get_correct_answer(question):
    return get_answer(question, is_correct=True)

def test_ask_without_seed(paul):
    # TODO: factor out with app.new_test_client, subclass it,
    # TODO: pass user (e.g PAUL) to its __init__ method and handle seeds etc
    rv = paul.get('/ask/{}/'.format(EASY_Q))
    assert rv.status_code == 302
    assert re.search(matches_any_ask_url(EASY_Q), rv.location)

def test_team_scores(steve, paul, tim):
    steve.answer_correct(EASY_Q)
    assert_team_score(TEAM_APPLE, num_users=1, score_sum=1)

    tim.answer_wrong(EASY_Q)
    assert_team_score(TEAM_APPLE, num_users=2, score_sum=1)

    paul.answer_correct(EASY_Q)
    assert_team_score(TEAM_APPLE, num_users=2, score_sum=1)  # paul is not in Apple team
    assert_team_score(TEAM_LINUX, num_users=1, score_sum=1)
    assert_team_score(TEAM_HN, num_users=1, score_sum=1)

    steve.answer_correct(MEDIUM_Q)
    assert_team_score(TEAM_APPLE, num_users=2, score_sum=3)

def assert_team_score(team, **expected):
    score = {k: int(v) for k, v in redis_store.hgetall('team:{}'.format(team)).viewitems()}
    for key, value in expected.viewitems():
        assert score[key] == value

# execute this test 10 times to thoroughly check random behaviour
@pytest.mark.parametrize('i', range(10))
def test_never_ask_the_same_question_twice_in_a_row(steve, i):
    # we need to answer every question, because otherwise
    # answer(steve, EASY_Q, ...) will always redirect to
    # the unanswered question.
    # We want to test that even if every question is answered,
    # then we don't ask the same question twice in row anyway.
    for question in models.Question.query.all():
        steve.answer_correct(question.id)

    rv = steve.answer_correct(EASY_Q)
    # TODO: check that absolute url is correct
    assert re.search(matches_any_ask_url(EASY_Q), rv.location) is None

@pytest.mark.parametrize('rank, num_users, expected_text', [
    (1, 1, 'top 1%'),
    (1, 2, 'top 1%'),
    (2, 2, 'bottom 50%'),
    (1, 3, 'top 1%'),
    (2, 3, 'top 50%'),
    (3, 3, 'bottom 33%'),
])
def test_get_score_text(rank, num_users, expected_text):
    assert get_score_text(rank, num_users) == expected_text

def test_ask_question_rendering(steve):
    rv = steve.ask_me(EASY_Q)
    # checking that XXX / 2 is highlighted
    assert '/ 2' in rv.data

def test_explain_question_rendering(steve):
    rv = steve.explain_to_me(EASY_Q)
    assert '__future__' in rv.data

def test_score_rendering(steve):
    steve.answer_correct(EASY_Q)  # so scores aren't empty
    rv = steve.checked_get('/score/')
    assert_has_score(rv, 1)
    assert '{} is your team'.format(TEAM_APPLE) in rv.data

def test_score_top_text(steve, paul):
    steve.answer_correct(EASY_Q)
    rv = steve.checked_get('/score/')
    assert "You're in the top 1%" in rv.data

    paul.answer_correct(MEDIUM_Q)
    rv = paul.checked_get('/score/')
    assert "You're in the top 1%" in rv.data

    rv = steve.checked_get('/score/')
    assert "You're in the bottom 50%" in rv.data

def test_score_during_ask(steve):
    rv = steve.ask_me(EASY_Q)
    assert_has_score(rv, 0)

# TODO: don't test markup with string comparisons, use css selectors
def assert_has_score(rv, expected_score):
    assert 'Score: {:d}'.format(expected_score) in rv.data
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
test_pykemon
----------------------------------

Tests for `pykemon` module.
"""

import unittest
import requests_mock
from beckett.exceptions import InvalidStatusCodeError
import pykemon

def base_get_test(self, resource, method="name"):
    """
    Base get test function for V2Client

    :param self: TestV2Client instance (self)
    :param resource: Resource to be tested
    :param method: 'name' or 'id' (sometimes resources only have one of them)
    """
    with requests_mock.mock() as mock:
        mock.get('%s/%s/1' % (self.base_url, resource), text=self.mock_data)
        response = getattr(self.client,
                           'get_%s' % resource.replace("-", "_"))(uid=1)[0]

        if method == "name":
            self.assertEqual(response.name, 'test_name')
        elif method == "id":
            self.assertEqual(response.id, 1)

def base_404_test(self, resource):
    """
    Base 404 error test function for V2Client

    :param self: TestV2Client instance (self)
    :param resource: Resource to be tested
    """
    with requests_mock.mock() as mock:
        mock.get('%s/%s/1' % (self.base_url, resource), status_code=404)
        self.assertRaises(
            InvalidStatusCodeError,
            lambda: getattr(self.client,
                            'get_%s' % resource.replace("-", "_"))(uid=1)[0])

class TestV2Client(unittest.TestCase):

    def setUp(self):
        self.client = pykemon.V2Client()
        self.mock_data = '{"id": 1, "name": "test_name"}'
        self.base_url = 'https://pokeapi.co/api/v2'

    def test_get_berry_resource(self):
        base_get_test(self, "berry")

    def test_get_berry_firmness_resource(self):
        base_get_test(self, "berry-firmness")

    def test_get_berry_flavor_firmness_resource(self):
        base_get_test(self, "berry-flavor")

    def test_get_contest_type_resource(self):
        base_get_test(self, "contest-type")

    def test_get_contest_effect_resource(self):
        base_get_test(self, "contest-effect", "id")

    def test_get_super_contest_effect_resource(self):
        base_get_test(self, "super-contest-effect", "id")

    def test_get_encounter_method_resource(self):
        base_get_test(self, "encounter-method")

    def test_get_encounter_condition_resource(self):
        base_get_test(self, "encounter-condition")

    def test_get_encounter_condition_value_resource(self):
        base_get_test(self, "encounter-condition-value")

    def test_get_evolution_chain_resource(self):
        base_get_test(self, "evolution-chain", "id")

    def test_get_evolution_trigger_resource(self):
        base_get_test(self, "evolution-trigger")

    def test_get_generation_resource(self):
        base_get_test(self, "generation")

    def test_get_pokedex_resource(self):
        base_get_test(self, "pokedex")

    def test_get_version_resource(self):
        base_get_test(self, "version")

    def test_get_version_group_resource(self):
        base_get_test(self, "version-group")

    def test_get_item_resource(self):
        base_get_test(self, "item")

    def test_get_item_attribute_resource(self):
        base_get_test(self, "item-attribute")

    def test_get_item_category_resource(self):
        base_get_test(self, "item-category")

    def test_get_item_fling_effect_resource(self):
        base_get_test(self, "item-fling-effect")

    def test_get_item_pocket_resource(self):
        base_get_test(self, "item-pocket")

    def test_get_machine_resource(self):
        base_get_test(self, "machine", "id")

    def test_get_move_resource(self):
        base_get_test(self, "move")

    def test_get_move_ailment_resource(self):
        base_get_test(self, "move-ailment")

    def test_get_move_battle_style_resource(self):
        base_get_test(self, "move-battle-style")

    def test_get_move_category_resource(self):
        base_get_test(self, "move-category")

    def test_get_move_damage_class_resource(self):
        base_get_test(self, "move-damage-class")

    def test_get_move_learn_method_resource(self):
        base_get_test(self, "move-learn-method")

    def test_get_move_target_resource(self):
        base_get_test(self, "move-target")

    def test_get_location_resource(self):
        base_get_test(self, "location")

    def test_get_location_area_resource(self):
        base_get_test(self, "location-area")

    def test_get_pal_park_area_resource(self):
        base_get_test(self, "pal-park-area")

    def test_get_region_resource(self):
        base_get_test(self, "region")

    def test_get_ability_resource(self):
        base_get_test(self, "ability")

    def test_get_characteristic_resource(self):
        base_get_test(self, "characteristic", "id")

    def test_get_egg_group_resource(self):
        base_get_test(self, "egg-group")

    def test_get_gender_resource(self):
        base_get_test(self, "gender")

    def test_get_growth_rate_resource(self):
        base_get_test(self, "growth-rate")

    def test_get_nature_resource(self):
        base_get_test(self, "nature")

    def test_get_pokeathlon_stat_resource(self):
        base_get_test(self, "pokeathlon-stat")

    def test_get_pokemon_resource(self):
        base_get_test(self, "pokemon")

    def test_get_pokemon_color_resource(self):
        base_get_test(self, "pokemon-color")

    def test_get_pokemon_form_resource(self):
        base_get_test(self, "pokemon-form")

    def test_get_pokemon_habitat_resource(self):
        base_get_test(self, "pokemon-habitat")

    def test_get_pokemon_shape_resource(self):
        base_get_test(self, "pokemon-shape")

    def test_get_pokemon_species_resource(self):
        base_get_test(self, "pokemon-species")

    def test_get_stat_resource(self):
        base_get_test(self, "stat")

    def test_get_type_resource(self):
        base_get_test(self, "type")

    def test_get_language_resource(self):
        base_get_test(self, "language")

    def test_404_berry_resource(self):
        base_404_test(self, "berry")

    def test_404_berry_firmness_resource(self):
        base_404_test(self, "berry-firmness")

    def test_404_berry_flavor_firmness_resource(self):
        base_404_test(self, "berry-flavor")

    def test_404_contest_type_resource(self):
        base_404_test(self, "contest-type")

    def test_404_contest_effect_resource(self):
        base_404_test(self, "contest-effect")

    def test_404_super_contest_effect_resource(self):
        base_404_test(self, "super-contest-effect")

    def test_404_encounter_method_resource(self):
        base_404_test(self, "encounter-method")

    def test_404_encounter_condition_resource(self):
        base_404_test(self, "encounter-condition")

    def test_404_encounter_condition_value_resource(self):
        base_404_test(self, "encounter-condition-value")

    def test_404_evolution_chain_resource(self):
        base_404_test(self, "evolution-chain")

    def test_404_evolution_trigger_resource(self):
        base_404_test(self, "evolution-trigger")

    def test_404_generation_resource(self):
        base_404_test(self, "generation")

    def test_404_pokedex_resource(self):
        base_404_test(self, "pokedex")

    def test_404_version_resource(self):
        base_404_test(self, "version")

    def test_404_version_group_resource(self):
        base_404_test(self, "version-group")

    def test_404_item_resource(self):
        base_404_test(self, "item")

    def test_404_item_attribute_resource(self):
        base_404_test(self, "item-attribute")

    def test_404_item_category_resource(self):
        base_404_test(self, "item-category")

    def test_404_item_fling_effect_resource(self):
        base_404_test(self, "item-fling-effect")

    def test_404_item_pocket_resource(self):
        base_404_test(self, "item-pocket")

    def test_404_machine_resource(self):
        base_404_test(self, "machine")

    def test_404_move_resource(self):
        base_404_test(self, "move")

    def test_404_move_ailment_resource(self):
        base_404_test(self, "move-ailment")

    def test_404_move_battle_style_resource(self):
        base_404_test(self, "move-battle-style")

    def test_404_move_category_resource(self):
        base_404_test(self, "move-category")

    def test_404_move_damage_class_resource(self):
        base_404_test(self, "move-damage-class")

    def test_404_move_learn_method_resource(self):
        base_404_test(self, "move-learn-method")

    def test_404_move_target_resource(self):
        base_404_test(self, "move-target")

    def test_404_location_resource(self):
        base_404_test(self, "location")

    def test_404_location_area_resource(self):
        base_404_test(self, "location-area")

    def test_404_pal_park_area_resource(self):
        base_404_test(self, "pal-park-area")

    def test_404_region_resource(self):
        base_404_test(self, "region")

    def test_404_ability_resource(self):
        base_404_test(self, "ability")

    def test_404_characteristic_resource(self):
        base_404_test(self, "characteristic")

    def test_404_egg_group_resource(self):
        base_404_test(self, "egg-group")

    def test_404_gender_resource(self):
        base_404_test(self, "gender")

    def test_404_growth_rate_resource(self):
        base_404_test(self, "growth-rate")

    def test_404_nature_resource(self):
        base_404_test(self, "nature")

    def test_404_pokeathlon_stat_resource(self):
        base_404_test(self, "pokeathlon-stat")

    def test_404_pokemon_resource(self):
        base_404_test(self, "pokemon")

    def test_404_pokemon_color_resource(self):
        base_404_test(self, "pokemon-color")

    def test_404_pokemon_form_resource(self):
        base_404_test(self, "pokemon-form")

    def test_404_pokemon_habitat_resource(self):
        base_404_test(self, "pokemon-habitat")

    def test_404_pokemon_shape_resource(self):
        base_404_test(self, "pokemon-shape")

    def test_404_pokemon_species_resource(self):
        base_404_test(self, "pokemon-species")

    def test_404_stat_resource(self):
        base_404_test(self, "stat")

    def test_404_type_resource(self):
        base_404_test(self, "type")

    def test_404_language_resource(self):
        base_404_test(self, "language")

if __name__ == '__main__':
    unittest.main()
<commit_msg>test code without using 'uid=' as parameter<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
test_pykemon
----------------------------------

Tests for `pykemon` module.
"""

import unittest
import requests_mock
from beckett.exceptions import InvalidStatusCodeError
import pykemon

def base_get_test(self, resource, method="name"):
    """
    Base get test function for V2Client

    :param self: TestV2Client instance (self)
    :param resource: Resource to be tested
    :param method: 'name' or 'id' (sometimes resources only have one of them)
    """
    with requests_mock.mock() as mock:
        mock.get('%s/%s/1' % (self.base_url, resource), text=self.mock_data)
        response = getattr(self.client,
                           'get_%s' % resource.replace("-", "_"))(1)[0]

        if method == "name":
            self.assertEqual(response.name, 'test_name')
        elif method == "id":
            self.assertEqual(response.id, 1)

def base_404_test(self, resource):
    """
    Base 404 error test function for V2Client

    :param self: TestV2Client instance (self)
    :param resource: Resource to be tested
    """
    with requests_mock.mock() as mock:
        mock.get('%s/%s/1' % (self.base_url, resource), status_code=404)
        self.assertRaises(
            InvalidStatusCodeError,
            lambda: getattr(self.client,
                            'get_%s' % resource.replace("-", "_"))(1)[0])

class TestV2Client(unittest.TestCase):

    def setUp(self):
        self.client = pykemon.V2Client()
        self.mock_data = '{"id": 1, "name": "test_name"}'
        self.base_url = 'https://pokeapi.co/api/v2'

    def test_get_berry_resource(self):
        base_get_test(self, "berry")

    def test_get_berry_firmness_resource(self):
        base_get_test(self, "berry-firmness")

    def test_get_berry_flavor_firmness_resource(self):
        base_get_test(self, "berry-flavor")

    def test_get_contest_type_resource(self):
        base_get_test(self, "contest-type")

    def test_get_contest_effect_resource(self):
        base_get_test(self, "contest-effect", "id")

    def test_get_super_contest_effect_resource(self):
        base_get_test(self, "super-contest-effect", "id")

    def test_get_encounter_method_resource(self):
        base_get_test(self, "encounter-method")

    def test_get_encounter_condition_resource(self):
        base_get_test(self, "encounter-condition")

    def test_get_encounter_condition_value_resource(self):
        base_get_test(self, "encounter-condition-value")

    def test_get_evolution_chain_resource(self):
        base_get_test(self, "evolution-chain", "id")

    def test_get_evolution_trigger_resource(self):
        base_get_test(self, "evolution-trigger")

    def test_get_generation_resource(self):
        base_get_test(self, "generation")

    def test_get_pokedex_resource(self):
        base_get_test(self, "pokedex")

    def test_get_version_resource(self):
        base_get_test(self, "version")

    def test_get_version_group_resource(self):
        base_get_test(self, "version-group")

    def test_get_item_resource(self):
        base_get_test(self, "item")

    def test_get_item_attribute_resource(self):
        base_get_test(self, "item-attribute")

    def test_get_item_category_resource(self):
        base_get_test(self, "item-category")

    def test_get_item_fling_effect_resource(self):
        base_get_test(self, "item-fling-effect")

    def test_get_item_pocket_resource(self):
        base_get_test(self, "item-pocket")

    def test_get_machine_resource(self):
        base_get_test(self, "machine", "id")

    def test_get_move_resource(self):
        base_get_test(self, "move")

    def test_get_move_ailment_resource(self):
        base_get_test(self, "move-ailment")

    def test_get_move_battle_style_resource(self):
        base_get_test(self, "move-battle-style")

    def test_get_move_category_resource(self):
        base_get_test(self, "move-category")

    def test_get_move_damage_class_resource(self):
        base_get_test(self, "move-damage-class")

    def test_get_move_learn_method_resource(self):
        base_get_test(self, "move-learn-method")

    def test_get_move_target_resource(self):
        base_get_test(self, "move-target")

    def test_get_location_resource(self):
        base_get_test(self, "location")

    def test_get_location_area_resource(self):
        base_get_test(self, "location-area")

    def test_get_pal_park_area_resource(self):
        base_get_test(self, "pal-park-area")

    def test_get_region_resource(self):
        base_get_test(self, "region")

    def test_get_ability_resource(self):
        base_get_test(self, "ability")

    def test_get_characteristic_resource(self):
        base_get_test(self, "characteristic", "id")

    def test_get_egg_group_resource(self):
        base_get_test(self, "egg-group")

    def test_get_gender_resource(self):
        base_get_test(self, "gender")

    def test_get_growth_rate_resource(self):
        base_get_test(self, "growth-rate")

    def test_get_nature_resource(self):
        base_get_test(self, "nature")

    def test_get_pokeathlon_stat_resource(self):
        base_get_test(self, "pokeathlon-stat")

    def test_get_pokemon_resource(self):
        base_get_test(self, "pokemon")

    def test_get_pokemon_color_resource(self):
        base_get_test(self, "pokemon-color")

    def test_get_pokemon_form_resource(self):
        base_get_test(self, "pokemon-form")

    def test_get_pokemon_habitat_resource(self):
        base_get_test(self, "pokemon-habitat")

    def test_get_pokemon_shape_resource(self):
        base_get_test(self, "pokemon-shape")

    def test_get_pokemon_species_resource(self):
        base_get_test(self, "pokemon-species")

    def test_get_stat_resource(self):
        base_get_test(self, "stat")

    def test_get_type_resource(self):
        base_get_test(self, "type")

    def test_get_language_resource(self):
        base_get_test(self, "language")

    def test_404_berry_resource(self):
        base_404_test(self, "berry")

    def test_404_berry_firmness_resource(self):
        base_404_test(self, "berry-firmness")

    def test_404_berry_flavor_firmness_resource(self):
        base_404_test(self, "berry-flavor")

    def test_404_contest_type_resource(self):
        base_404_test(self, "contest-type")

    def test_404_contest_effect_resource(self):
        base_404_test(self, "contest-effect")

    def test_404_super_contest_effect_resource(self):
        base_404_test(self, "super-contest-effect")

    def test_404_encounter_method_resource(self):
        base_404_test(self, "encounter-method")

    def test_404_encounter_condition_resource(self):
        base_404_test(self, "encounter-condition")

    def test_404_encounter_condition_value_resource(self):
        base_404_test(self, "encounter-condition-value")

    def test_404_evolution_chain_resource(self):
        base_404_test(self, "evolution-chain")

    def test_404_evolution_trigger_resource(self):
        base_404_test(self, "evolution-trigger")

    def test_404_generation_resource(self):
        base_404_test(self, "generation")

    def test_404_pokedex_resource(self):
        base_404_test(self, "pokedex")

    def test_404_version_resource(self):
        base_404_test(self, "version")

    def test_404_version_group_resource(self):
        base_404_test(self, "version-group")

    def test_404_item_resource(self):
        base_404_test(self, "item")

    def test_404_item_attribute_resource(self):
        base_404_test(self, "item-attribute")

    def test_404_item_category_resource(self):
        base_404_test(self, "item-category")

    def test_404_item_fling_effect_resource(self):
        base_404_test(self, "item-fling-effect")

    def test_404_item_pocket_resource(self):
        base_404_test(self, "item-pocket")

    def test_404_machine_resource(self):
        base_404_test(self, "machine")

    def test_404_move_resource(self):
        base_404_test(self, "move")

    def test_404_move_ailment_resource(self):
        base_404_test(self, "move-ailment")

    def test_404_move_battle_style_resource(self):
        base_404_test(self, "move-battle-style")

    def test_404_move_category_resource(self):
        base_404_test(self, "move-category")

    def test_404_move_damage_class_resource(self):
        base_404_test(self, "move-damage-class")

    def test_404_move_learn_method_resource(self):
        base_404_test(self, "move-learn-method")

    def test_404_move_target_resource(self):
        base_404_test(self, "move-target")

    def test_404_location_resource(self):
        base_404_test(self, "location")

    def test_404_location_area_resource(self):
        base_404_test(self, "location-area")

    def test_404_pal_park_area_resource(self):
        base_404_test(self, "pal-park-area")

    def test_404_region_resource(self):
        base_404_test(self, "region")

    def test_404_ability_resource(self):
        base_404_test(self, "ability")

    def test_404_characteristic_resource(self):
        base_404_test(self, "characteristic")

    def test_404_egg_group_resource(self):
        base_404_test(self, "egg-group")

    def test_404_gender_resource(self):
        base_404_test(self, "gender")

    def test_404_growth_rate_resource(self):
        base_404_test(self, "growth-rate")

    def test_404_nature_resource(self):
        base_404_test(self, "nature")

    def test_404_pokeathlon_stat_resource(self):
        base_404_test(self, "pokeathlon-stat")

    def test_404_pokemon_resource(self):
        base_404_test(self, "pokemon")

    def test_404_pokemon_color_resource(self):
        base_404_test(self, "pokemon-color")

    def test_404_pokemon_form_resource(self):
        base_404_test(self, "pokemon-form")

    def test_404_pokemon_habitat_resource(self):
        base_404_test(self, "pokemon-habitat")

    def test_404_pokemon_shape_resource(self):
        base_404_test(self, "pokemon-shape")

    def test_404_pokemon_species_resource(self):
        base_404_test(self, "pokemon-species")

    def test_404_stat_resource(self):
        base_404_test(self, "stat")

    def test_404_type_resource(self):
        base_404_test(self, "type")

    def test_404_language_resource(self):
        base_404_test(self, "language")

if __name__ == '__main__':
    unittest.main()
<|endoftext|>


<commit_before># Copyright 2010-2011 OpenStack Foundation
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import datetime

from oslo_utils import timeutils

class ViewBuilder(object):
    """OpenStack API base limits view builder."""

    limit_names = {}

    def __init__(self):
        self.limit_names = {
            "ram": ["maxTotalRAMSize"],
            "instances": ["maxTotalInstances"],
            "cores": ["maxTotalCores"],
            "key_pairs": ["maxTotalKeypairs"],
            "floating_ips": ["maxTotalFloatingIps"],
            "metadata_items": ["maxServerMeta", "maxImageMeta"],
            "injected_files": ["maxPersonality"],
            "injected_file_content_bytes": ["maxPersonalitySize"],
            "security_groups": ["maxSecurityGroups"],
            "security_group_rules": ["maxSecurityGroupRules"],
    }

    def build(self, rate_limits, absolute_limits):
        rate_limits = self._build_rate_limits(rate_limits)
        absolute_limits = self._build_absolute_limits(absolute_limits)

        output = {
            "limits": {
                "rate": rate_limits,
                "absolute": absolute_limits,
            },
        }

        return output

    def _build_absolute_limits(self, absolute_limits):
        """Builder for absolute limits

        absolute_limits should be given as a dict of limits.
        For example: {"ram": 512, "gigabytes": 1024}.

        """
        limits = {}
        for name, value in absolute_limits.iteritems():
            if name in self.limit_names and value is not None:
                for name in self.limit_names[name]:
                    limits[name] = value
        return limits

    def _build_rate_limits(self, rate_limits):
        limits = []
        for rate_limit in rate_limits:
            _rate_limit_key = None
            _rate_limit = self._build_rate_limit(rate_limit)

            # check for existing key
            for limit in limits:
                if (limit["uri"] == rate_limit["URI"] and
                        limit["regex"] == rate_limit["regex"]):
                    _rate_limit_key = limit
                    break

            # ensure we have a key if we didn't find one
            if not _rate_limit_key:
                _rate_limit_key = {
                    "uri": rate_limit["URI"],
                    "regex": rate_limit["regex"],
                    "limit": [],
                }
                limits.append(_rate_limit_key)

            _rate_limit_key["limit"].append(_rate_limit)

        return limits

    def _build_rate_limit(self, rate_limit):
        _get_utc = datetime.datetime.utcfromtimestamp
        next_avail = _get_utc(rate_limit["resetTime"])
        return {
            "verb": rate_limit["verb"],
            "value": rate_limit["value"],
            "remaining": int(rate_limit["remaining"]),
            "unit": rate_limit["unit"],
            "next-available": timeutils.isotime(at=next_avail),
        }

class ViewBuilderV3(ViewBuilder):

    def __init__(self):
        super(ViewBuilderV3, self).__init__()
        # NOTE In v2.0 these are added by a specific extension
        self.limit_names["server_groups"] = ["maxServerGroups"]
        self.limit_names["server_group_members"] = ["maxServerGroupMembers"]
<commit_msg>Variable 'name' already declared in 'for' loop<commit_after># Copyright 2010-2011 OpenStack Foundation
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import datetime

from oslo_utils import timeutils

class ViewBuilder(object):
    """OpenStack API base limits view builder."""

    limit_names = {}

    def __init__(self):
        self.limit_names = {
            "ram": ["maxTotalRAMSize"],
            "instances": ["maxTotalInstances"],
            "cores": ["maxTotalCores"],
            "key_pairs": ["maxTotalKeypairs"],
            "floating_ips": ["maxTotalFloatingIps"],
            "metadata_items": ["maxServerMeta", "maxImageMeta"],
            "injected_files": ["maxPersonality"],
            "injected_file_content_bytes": ["maxPersonalitySize"],
            "security_groups": ["maxSecurityGroups"],
            "security_group_rules": ["maxSecurityGroupRules"],
    }

    def build(self, rate_limits, absolute_limits):
        rate_limits = self._build_rate_limits(rate_limits)
        absolute_limits = self._build_absolute_limits(absolute_limits)

        output = {
            "limits": {
                "rate": rate_limits,
                "absolute": absolute_limits,
            },
        }

        return output

    def _build_absolute_limits(self, absolute_limits):
        """Builder for absolute limits

        absolute_limits should be given as a dict of limits.
        For example: {"ram": 512, "gigabytes": 1024}.

        """
        limits = {}
        for name, value in absolute_limits.iteritems():
            if name in self.limit_names and value is not None:
                for limit_name in self.limit_names[name]:
                    limits[limit_name] = value
        return limits

    def _build_rate_limits(self, rate_limits):
        limits = []
        for rate_limit in rate_limits:
            _rate_limit_key = None
            _rate_limit = self._build_rate_limit(rate_limit)

            # check for existing key
            for limit in limits:
                if (limit["uri"] == rate_limit["URI"] and
                        limit["regex"] == rate_limit["regex"]):
                    _rate_limit_key = limit
                    break

            # ensure we have a key if we didn't find one
            if not _rate_limit_key:
                _rate_limit_key = {
                    "uri": rate_limit["URI"],
                    "regex": rate_limit["regex"],
                    "limit": [],
                }
                limits.append(_rate_limit_key)

            _rate_limit_key["limit"].append(_rate_limit)

        return limits

    def _build_rate_limit(self, rate_limit):
        _get_utc = datetime.datetime.utcfromtimestamp
        next_avail = _get_utc(rate_limit["resetTime"])
        return {
            "verb": rate_limit["verb"],
            "value": rate_limit["value"],
            "remaining": int(rate_limit["remaining"]),
            "unit": rate_limit["unit"],
            "next-available": timeutils.isotime(at=next_avail),
        }

class ViewBuilderV3(ViewBuilder):

    def __init__(self):
        super(ViewBuilderV3, self).__init__()
        # NOTE In v2.0 these are added by a specific extension
        self.limit_names["server_groups"] = ["maxServerGroups"]
        self.limit_names["server_group_members"] = ["maxServerGroupMembers"]
<|endoftext|>


<commit_before>from __future__ import division, print_function, absolute_import

import numpy
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier, AdaBoostClassifier, \
    RandomForestRegressor, GradientBoostingRegressor, AdaBoostRegressor
from sklearn.metrics import mean_squared_error

from rep.data.storage import LabeledDataStorage
from rep.metaml import ClassifiersFactory, RegressorsFactory
from rep.test.test_estimators import generate_classification_sample, generate_regression_sample
from rep.report.metrics import RocAuc

__author__ = 'Alex Rogozhnikov'

# Important:
# unfortunately, testing is very complicated, so only workability is tested

def _test_classification_report(n_classes=2):
    classifiers = ClassifiersFactory()
    classifiers.add_classifier('gb', GradientBoostingClassifier(n_estimators=10))
    classifiers.add_classifier('rf', RandomForestClassifier())
    classifiers.add_classifier('ada', AdaBoostClassifier(n_estimators=10))

    X, y = generate_classification_sample(1000, 5, n_classes=n_classes)
    classifiers.fit(X, y)

    X, y = generate_classification_sample(1000, 5, n_classes=n_classes)
    test_lds = LabeledDataStorage(X, y, sample_weight=None)
    report = classifiers.test_on_lds(test_lds)

    val = numpy.mean(X['column0'])
    labels_dict = None
    if n_classes > 2:
        labels_dict = {i: str(i) for i in range(n_classes)}
    _classification_mask_report(report, "column0 > %f" % val, X, labels_dict)
    _classification_mask_report(report, lambda x: numpy.array(x['column0']) < val, X, labels_dict)
    _classification_mask_report(report, None, X, labels_dict)

def test_classification_report():
    _test_classification_report()

def test_multiclassification_report():
    _test_classification_report(n_classes=4)

def _classification_mask_report(report, mask, X, labels_dict):
    report.features_correlation_matrix(mask=mask).plot()
    report.features_correlation_matrix_by_class(mask=mask, labels_dict=labels_dict).plot()
    report.efficiencies(features=X.columns[1:3], mask=mask, labels_dict=labels_dict).plot()
    report.features_pdf(mask=mask, labels_dict=labels_dict).plot()
    report.learning_curve(RocAuc(), mask=mask, metric_label='roc').plot()
    significance = lambda s, b:  s / (numpy.sqrt(b) + 0.01)
    report.metrics_vs_cut(significance, mask=mask, metric_label='sign').plot()
    report.prediction_pdf(mask=mask, labels_dict=labels_dict).plot()
    report.scatter([X.columns[:2], X.columns[1:3]], mask=mask, labels_dict=labels_dict).plot()
    report.feature_importance().plot()
    if labels_dict is None:
        report.feature_importance_shuffling(mask=mask).plot()
        report.roc(mask=mask).plot()
    report.efficiencies_2d(['column0', 'column1'], 0.3, mask=mask, labels_dict=labels_dict)
    print(report.compute_metric(RocAuc()))

def test_regression_report():
    regressors = RegressorsFactory()
    regressors.add_regressor('gb', GradientBoostingRegressor(n_estimators=10))
    regressors.add_regressor('rf', RandomForestRegressor())
    regressors.add_regressor('ada', AdaBoostRegressor(n_estimators=10))

    X, y = generate_regression_sample(1000, 5)
    regressors.fit(X, y)

    X, y = generate_regression_sample(1000, 5)
    test_lds = LabeledDataStorage(X, y, sample_weight=None)
    regression_report = regressors.test_on_lds(test_lds)
    val = numpy.mean(X['column0'])
    _regression_mask_report(regression_report, "column0 > %f" % val, X)
    _regression_mask_report(regression_report, lambda x: numpy.array(x['column0']) < val, X)
    _regression_mask_report(regression_report, None, X)

def _regression_mask_report(report, mask, X):
    report.features_correlation_matrix(mask=mask).plot()
    report.learning_curve(mean_squared_error, mask=mask, metric_label='mse').plot()

    report.scatter([X.columns[:2], X.columns[1:3]], mask=mask).plot()
    report.predictions_scatter(mask=mask).plot()
    report.features_correlation_matrix(mask=mask).plot()
    report.feature_importance().plot()
    report.feature_importance_shuffling(mask=mask).plot()
    print(report.compute_metric(mean_squared_error))
<commit_msg>added tests for predict_only_masked<commit_after>from __future__ import division, print_function, absolute_import

import numpy
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier, AdaBoostClassifier, \
    RandomForestRegressor, GradientBoostingRegressor, AdaBoostRegressor
from sklearn.metrics import mean_squared_error, log_loss

from rep.data.storage import LabeledDataStorage
from rep.metaml import ClassifiersFactory, RegressorsFactory
from rep.test.test_estimators import generate_classification_sample, generate_regression_sample
from rep.report.metrics import RocAuc, LogLoss

__author__ = 'Alex Rogozhnikov'

# Important:
# unfortunately, testing is very complicated, so only workability is tested

def check_classification_learning_curve_masks(report, n_classes):
    """testing predict_only_mask option"""
    for mask in [None, "column0 > 0", "column0 > -0.5"]:
        if n_classes == 2:
            loss = RocAuc()
        else:
            loss = log_loss
        lc1 = report.learning_curve(loss, mask=mask, predict_only_masked=True, steps=3)
        lc2 = report.learning_curve(loss, mask=mask, predict_only_masked=False, steps=3)
        assert lc1.functions == lc2.functions

def check_regression_learning_curve_masks(report):
    """testing predict_only_mask option"""
    for mask in [None, "column0 > 0", "column0 > -0.5"]:
        loss = mean_squared_error
        lc1 = report.learning_curve(loss, mask=mask, predict_only_masked=True, steps=3)
        lc2 = report.learning_curve(loss, mask=mask, predict_only_masked=False, steps=3)
        assert lc1.functions == lc2.functions

def _classification_mask_report(report, mask, X, labels_dict):
    report.features_correlation_matrix(mask=mask).plot()
    report.features_correlation_matrix_by_class(mask=mask, labels_dict=labels_dict).plot()
    report.efficiencies(features=X.columns[1:3], mask=mask, labels_dict=labels_dict).plot()
    report.features_pdf(mask=mask, labels_dict=labels_dict).plot()
    report.learning_curve(RocAuc(), mask=mask, metric_label='roc').plot()
    significance = lambda s, b: s / (numpy.sqrt(b) + 0.01)
    report.metrics_vs_cut(significance, mask=mask, metric_label='sign').plot()
    report.prediction_pdf(mask=mask, labels_dict=labels_dict).plot()
    report.scatter([X.columns[:2], X.columns[1:3]], mask=mask, labels_dict=labels_dict).plot()
    report.feature_importance().plot()
    if labels_dict is None:
        report.feature_importance_shuffling(mask=mask).plot()
        report.roc(mask=mask).plot()
    report.efficiencies_2d(['column0', 'column1'], 0.3, mask=mask, labels_dict=labels_dict)
    print(report.compute_metric(RocAuc()))

def _check_classification_report(n_classes=2):
    classifiers = ClassifiersFactory()
    classifiers.add_classifier('gb', GradientBoostingClassifier(n_estimators=10))
    classifiers.add_classifier('rf', RandomForestClassifier())
    classifiers.add_classifier('ada', AdaBoostClassifier(n_estimators=10))

    X, y = generate_classification_sample(1000, 5, n_classes=n_classes)
    classifiers.fit(X, y)

    X, y = generate_classification_sample(1000, 5, n_classes=n_classes)
    test_lds = LabeledDataStorage(X, y, sample_weight=None)
    report = classifiers.test_on_lds(test_lds)

    val = numpy.mean(X['column0'])
    labels_dict = None
    if n_classes > 2:
        labels_dict = {i: str(i) for i in range(n_classes)}
    _classification_mask_report(report, "column0 > %f" % val, X, labels_dict)
    _classification_mask_report(report, lambda x: numpy.array(x['column0']) < val, X, labels_dict)
    _classification_mask_report(report, None, X, labels_dict)
    check_classification_learning_curve_masks(report, n_classes=n_classes)

def test_classification_report():
    _check_classification_report(n_classes=2)

def test_multiclassification_report():
    _check_classification_report(n_classes=4)

def test_regression_report():
    regressors = RegressorsFactory()
    regressors.add_regressor('gb', GradientBoostingRegressor(n_estimators=10))
    regressors.add_regressor('rf', RandomForestRegressor())
    regressors.add_regressor('ada', AdaBoostRegressor(n_estimators=10))

    X, y = generate_regression_sample(1000, 5)
    regressors.fit(X, y)

    X, y = generate_regression_sample(1000, 5)
    test_lds = LabeledDataStorage(X, y, sample_weight=None)
    regression_report = regressors.test_on_lds(test_lds)
    val = numpy.mean(X['column0'])
    _regression_mask_report(regression_report, "column0 > %f" % val, X)
    _regression_mask_report(regression_report, lambda x: numpy.array(x['column0']) < val, X)
    _regression_mask_report(regression_report, None, X)
    check_regression_learning_curve_masks(regression_report)

def _regression_mask_report(report, mask, X):
    report.features_correlation_matrix(mask=mask).plot()
    report.learning_curve(mean_squared_error, mask=mask, metric_label='mse').plot()

    report.scatter([X.columns[:2], X.columns[1:3]], mask=mask).plot()
    report.predictions_scatter(mask=mask).plot()
    report.features_correlation_matrix(mask=mask).plot()
    report.feature_importance().plot()
    report.feature_importance_shuffling(mask=mask).plot()
    print(report.compute_metric(mean_squared_error))
<|endoftext|>


<commit_before>import pytest

from flagon.request import Request
from flagon.exceptions import BadRequest, NotFound, MethodNotAllowed
from flagon.datastructures import MultiDict
import copy

env1 = {
    'REQUEST_METHOD':       'GET',
    'SCRIPT_NAME':          '/foo',
    'PATH_INFO':            '/bar',
    'QUERY_STRING':         'a=1&b=2',
    'SERVER_NAME':          'test.flagon.org',
    'SERVER_PORT':          80,
    'HTTP_HOST':            'test.flagon.org',
    'SERVER_PROTOCOL':      'http',
    'CONTENT_TYPE':         '',
    'CONTENT_LENGTH':       '0',
    'wsgi.url_scheme':      'http'
}

def test_basic_request():
    env = dict(copy.deepcopy(env1))
    req = Request(env)
    assert 'flagon.request' in env
    assert req.args == MultiDict({'a':'1', 'b':'2'}.items())
    assert req.values == MultiDict({'a':'1', 'b':'2'}.items())
    assert req.path == '/bar'
    assert req.full_path == '/foo/bar'
    assert req.script_root == '/foo'
    assert req.url == 'http://test.flagon.org/foo/bar?a=1&b=2'
    assert req.base_url == 'http://test.flagon.org/foo/bar'
    assert req.root_url == 'http://test.flagon.org/foo/'
    assert req.host_url == 'http://test.flagon.org/'
    assert req.host == 'test.flagon.org'
<commit_msg>add some req test<commit_after>import pytest

from flagon.request import Request
from flagon.exceptions import BadRequest, NotFound, MethodNotAllowed
from flagon.datastructures import MultiDict
import copy

env1 = {
    'REQUEST_METHOD':       'GET',
    'SCRIPT_NAME':          '/foo',
    'PATH_INFO':            '/bar',
    'QUERY_STRING':         'a=1&b=2',
    'SERVER_NAME':          'test.flagon.org',
    'SERVER_PORT':          80,
    'HTTP_HOST':            'test.flagon.org',
    'SERVER_PROTOCOL':      'http',
    'CONTENT_TYPE':         '',
    'CONTENT_LENGTH':       '0',
    'wsgi.url_scheme':      'http'
}

def test_basic_request():
    env = dict(copy.deepcopy(env1))
    req = Request(env)
    assert 'flagon.request' in env
    assert req.args == MultiDict({'a':'1', 'b':'2'}.items())
    assert req.values == MultiDict({'a':'1', 'b':'2'}.items())
    assert req.path == '/bar'
    assert req.full_path == '/foo/bar'
    assert req.script_root == '/foo'
    assert req.url == 'http://test.flagon.org/foo/bar?a=1&b=2'
    assert req.base_url == 'http://test.flagon.org/foo/bar'
    assert req.root_url == 'http://test.flagon.org/foo/'
    assert req.host_url == 'http://test.flagon.org/'
    assert req.host == 'test.flagon.org'
    assert req.get_data() == ''
<|endoftext|>


<commit_before>"""
Service API Tests
"""

# stdlib
import unittest

# library
import pytest

# module
from avwx import exceptions, service

class TestService(unittest.TestCase):

    serv: service.Service
    name: str = "Service"
    stations: [str] = None

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.serv = getattr(service, self.name)("metar")
        if not self.stations:
            self.stations = []

    def test_init(self):
        """
        Tests that the Service class is initialized properly
        """
        for attr in ("url", "rtype", "_make_err", "_extract", "fetch"):
            self.assertTrue(hasattr(self.serv, attr))
        self.assertEqual(self.serv.rtype, "metar")

    def test_service(self):
        """
        Tests that the base Service class has no URL and throws NotImplemented errors
        """
        if type(self.serv) == service.Service:
            self.assertIsNone(self.serv.url)
            with self.assertRaises(NotImplementedError):
                self.serv._extract(None)
        else:
            self.assertIsInstance(self.serv.url, str)
        self.assertIsInstance(self.serv.method, str)
        self.assertIn(self.serv.method, ("GET", "POST"))

    def test_make_err(self):
        """
        Tests that InvalidRequest exceptions are generated with the right message
        """
        key, msg = "test_key", "testing"
        err = self.serv._make_err(msg, key)
        err_str = (
            f"Could not find {key} in {self.serv.__class__.__name__} response\n{msg}"
        )
        self.assertIsInstance(err, exceptions.InvalidRequest)
        self.assertEqual(err.args, (err_str,))
        self.assertEqual(str(err), err_str)

    def test_fetch_exceptions(self):
        """
        Tests fetch exception handling
        """
        for station in ("12K", "MAYT"):
            with self.assertRaises(exceptions.BadStation):
                self.serv.fetch(station)
        # Should raise exception due to empty url
        if self.name == "Service":
            with self.assertRaises(NotImplementedError):
                self.serv.fetch("KJFK")

    @pytest.mark.asyncio
    async def test_async_fetch_exceptions(self):
        """
        Tests async fetch exception handling
        """
        for station in ("12K", "MAYT"):
            with self.assertRaises(exceptions.BadStation):
                await self.serv.async_fetch(station)
        # Should raise exception due to empty url
        if self.name == "Service":
            with self.assertRaises(AttributeError):
                await self.serv.async_fetch("KJFK")

    def test_fetch(self):
        """
        Tests that reports are fetched from service
        """
        for station in self.stations:
            report = self.serv.fetch(station)
            self.assertIsInstance(report, str)
            self.assertTrue(station in report)

    @pytest.mark.asyncio
    async def test_async_fetch(self):
        """
        Tests that reports are fetched from async service
        """
        for station in self.stations:
            report = await self.serv.async_fetch(station)
            self.assertIsInstance(report, str)
            self.assertTrue(report.startswith(station))

class TestNOAA(TestService):

    name = "NOAA"
    stations = ["KJFK", "EGLL", "PHNL"]

class TestAMO(TestService):

    name = "AMO"
    stations = ["RKSI", "RKSS", "RKNY"]

class TestMAC(TestService):

    name = "MAC"
    stations = ["SKBO"]

class TestAUBOM(TestService):

    name = "AUBOM"
    stations = ["YWOL", "YSSY"]

class TestModule(unittest.TestCase):
    def test_get_service(self):
        """
        Tests that the correct service class is returned
        """
        for stations, country, serv in (
            (("KJFK", "PHNL"), "US", service.NOAA),
            (("EGLL",), "GB", service.NOAA),
            (("RKSI",), "KR", service.AMO),
            (("SKBO", "SKPP"), "CO", service.MAC),
            (("YWOL", "YSSY"), "AU", service.AUBOM),
        ):
            for station in stations:
                self.assertIsInstance(
                    service.get_service(station, country)("metar"), serv
                )
<commit_msg>Fix AUBOM test<commit_after>"""
Service API Tests
"""

# stdlib
import unittest

# library
import pytest

# module
from avwx import exceptions, service

class TestService(unittest.TestCase):

    serv: service.Service
    name: str = "Service"
    stations: [str] = None

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.serv = getattr(service, self.name)("metar")
        if not self.stations:
            self.stations = []

    def test_init(self):
        """
        Tests that the Service class is initialized properly
        """
        for attr in ("url", "rtype", "_make_err", "_extract", "fetch"):
            self.assertTrue(hasattr(self.serv, attr))
        self.assertEqual(self.serv.rtype, "metar")

    def test_service(self):
        """
        Tests that the base Service class has no URL and throws NotImplemented errors
        """
        if type(self.serv) == service.Service:
            self.assertIsNone(self.serv.url)
            with self.assertRaises(NotImplementedError):
                self.serv._extract(None)
        else:
            self.assertIsInstance(self.serv.url, str)
        self.assertIsInstance(self.serv.method, str)
        self.assertIn(self.serv.method, ("GET", "POST"))

    def test_make_err(self):
        """
        Tests that InvalidRequest exceptions are generated with the right message
        """
        key, msg = "test_key", "testing"
        err = self.serv._make_err(msg, key)
        err_str = (
            f"Could not find {key} in {self.serv.__class__.__name__} response\n{msg}"
        )
        self.assertIsInstance(err, exceptions.InvalidRequest)
        self.assertEqual(err.args, (err_str,))
        self.assertEqual(str(err), err_str)

    def test_fetch_exceptions(self):
        """
        Tests fetch exception handling
        """
        for station in ("12K", "MAYT"):
            with self.assertRaises(exceptions.BadStation):
                self.serv.fetch(station)
        # Should raise exception due to empty url
        if self.name == "Service":
            with self.assertRaises(NotImplementedError):
                self.serv.fetch("KJFK")

    @pytest.mark.asyncio
    async def test_async_fetch_exceptions(self):
        """
        Tests async fetch exception handling
        """
        for station in ("12K", "MAYT"):
            with self.assertRaises(exceptions.BadStation):
                await self.serv.async_fetch(station)
        # Should raise exception due to empty url
        if self.name == "Service":
            with self.assertRaises(AttributeError):
                await self.serv.async_fetch("KJFK")

    def test_fetch(self):
        """
        Tests that reports are fetched from service
        """
        for station in self.stations:
            report = self.serv.fetch(station)
            self.assertIsInstance(report, str)
            self.assertTrue(station in report)

    @pytest.mark.asyncio
    async def test_async_fetch(self):
        """
        Tests that reports are fetched from async service
        """
        for station in self.stations:
            report = await self.serv.async_fetch(station)
            self.assertIsInstance(report, str)
            self.assertTrue(report.startswith(station))

class TestNOAA(TestService):

    name = "NOAA"
    stations = ["KJFK", "EGLL", "PHNL"]

class TestAMO(TestService):

    name = "AMO"
    stations = ["RKSI", "RKSS", "RKNY"]

class TestMAC(TestService):

    name = "MAC"
    stations = ["SKBO"]

class TestAUBOM(TestService):

    name = "AUBOM"
    stations = ["YBBN", "YSSY"]

class TestModule(unittest.TestCase):
    def test_get_service(self):
        """
        Tests that the correct service class is returned
        """
        for stations, country, serv in (
            (("KJFK", "PHNL"), "US", service.NOAA),
            (("EGLL",), "GB", service.NOAA),
            (("RKSI",), "KR", service.AMO),
            (("SKBO", "SKPP"), "CO", service.MAC),
            (("YWOL", "YSSY"), "AU", service.AUBOM),
        ):
            for station in stations:
                self.assertIsInstance(
                    service.get_service(station, country)("metar"), serv
                )
<|endoftext|>