<commit_before>import unittest
import os
import uuid
import warnings
import logging

import signac
from signac.common import six

from test_job import BaseJobTest

if six.PY2:
    logging.basicConfig(level=logging.WARNING)

# Make sure the jobs created for this test are unique.
test_token = {'test_token': str(uuid.uuid4())}

warnings.simplefilter('default')
warnings.filterwarnings('error', category=DeprecationWarning, module='signac')

class BaseProjectTest(BaseJobTest):
    pass

class ProjectTest(BaseProjectTest):

    def test_get(self):
        pass

    def test_get_id(self):
        self.assertEqual(self.project.get_id(), self.config['project'])
        self.assertEqual(str(self.project), self.project.get_id())

    def test_root_directory(self):
        self.assertEqual(self._tmp_pr, self.project.root_directory())

    def test_workspace_directory(self):
        self.assertEqual(self._tmp_wd, self.project.workspace())

    def test_workspace_directory_with_env_variable(self):
        os.environ['SIGNAC_ENV_DIR_TEST'] = self._tmp_wd
        self.project.config['workspace_dir'] = '${SIGNAC_ENV_DIR_TEST}'
        self.assertEqual(self._tmp_wd, self.project.workspace())

    def test_write_read_statepoint(self):
        statepoints = [{'a': i} for i in range(5)]
        self.project.dump_statepoints(statepoints)
        self.project.write_statepoints(statepoints)
        read = list(self.project.read_statepoints().values())
        self.assertEqual(len(read), len(statepoints))
        more_statepoints = [{'b': i} for i in range(5, 10)]
        self.project.write_statepoints(more_statepoints)
        read2 = list(self.project.read_statepoints())
        self.assertEqual(len(read2), len(statepoints) + len(more_statepoints))
        for id_ in self.project.read_statepoints().keys():
            self.project.get_statepoint(id_)

    def test_find_statepoints(self):
        statepoints = [{'a': i} for i in range(5)]
        for sp in statepoints:
            self.project.open_job(sp).init()
        self.assertEqual(
            len(statepoints),
            len(list(self.project.find_statepoints())))
        self.assertEqual(
            1, len(list(self.project.find_statepoints({'a': 0}))))

    def test_find_statepoint_sequences(self):
        statepoints = [{'a': (i, i+1)} for i in range(5)]
        for sp in statepoints:
            self.project.open_job(sp).init()
        self.assertEqual(
            len(statepoints),
            len(list(self.project.find_statepoints())))
        self.assertEqual(
            1,
            len(list(self.project.find_statepoints({'a': [0, 1]}))))
        self.assertEqual(
            1,
            len(list(self.project.find_statepoints({'a': (0, 1)}))))

    def test_find_jobs(self):
        statepoints = [{'a': i} for i in range(5)]
        for sp in statepoints:
            self.project.open_job(sp).document['test'] = True
        self.assertEqual(len(statepoints), len(list(self.project.find_jobs())))
        self.assertEqual(1, len(list(self.project.find_jobs({'a': 0}))))
        self.assertEqual(0, len(list(self.project.find_jobs({'a': 5}))))

    def test_num_jobs(self):
        statepoints = [{'a': i} for i in range(5)]
        for sp in statepoints:
            self.project.open_job(sp).init()
        self.assertEqual(len(statepoints), self.project.num_jobs())
        self.assertEqual(len(statepoints), len(list(self.project.find_jobs())))

    def test_open_job_by_id(self):
        statepoints = [{'a': i} for i in range(5)]
        jobs = [self.project.open_job(sp) for sp in statepoints]
        try:
            logging.disable(logging.WARNING)
            for job in jobs:
                with self.assertRaises(KeyError):
                    self.project.open_job(id=str(job))
            for job in jobs:
                job.init()
            for job in jobs:
                self.project.open_job(id=str(job))
            with self.assertRaises(KeyError):
                self.project.open_job(id='abc')
            with self.assertRaises(ValueError):
                self.project.open_job()
            with self.assertRaises(ValueError):
                self.project.open_job(statepoints[0], id=str(jobs[0]))
        finally:
            logging.disable(logging.NOTSET)

    def test_create_view(self):
        # Test for highly heterogenous parameter space
        sp_0 = [{'a': i, 'b': 0} for i in range(5)]
        sp_1 = [{'a': i, 'b': 0, 'c': {'a': i, 'b': 0}} for i in range(5)]
        sp_2 = [{'a': i, 'b': 0, 'c': {'a': i, 'b': 0, 'c': {'a': i, 'b': 0}}}
                for i in range(5)]
        statepoints = sp_0 + sp_1 + sp_2
        for sp in statepoints:
            self.project.open_job(sp).document['test'] = True
        key_set = list(signac.contrib.project._find_unique_keys(statepoints))
        self.assertEqual(len(statepoints), len(
            list(signac.contrib.project._make_urls(statepoints, key_set))))
        view_prefix = os.path.join(self._tmp_pr, 'view')
        self.project.create_view(prefix=view_prefix)
        self.assertTrue(os.path.isdir(view_prefix))

    def test_find_job_documents(self):
        statepoints = [{'a': i} for i in range(5)]
        for sp in statepoints:
            self.project.open_job(sp).document['test'] = True
        self.assertEqual(
            len(list(self.project.find_job_documents({'a': 0}))), 1)
        job_docs = list(self.project.find_job_documents())
        self.assertEqual(len(statepoints), len(job_docs))
        for job_doc in job_docs:
            sp = job_doc['statepoint']
            self.assertEqual(str(self.project.open_job(sp)), job_doc['_id'])

    def test_find_job_documents_illegal_key(self):
        statepoints = [{'a': i} for i in range(5)]
        for sp in statepoints:
            self.project.open_job(sp).document['test'] = True
        list(self.project.find_job_documents())
        self.assertEqual(len(statepoints), len(
            list(self.project.find_job_documents())))
        self.project.open_job({'a': 0}).document['_id'] = True
        list(self.project.find_job_documents({'a': 1}))  # should not throw
        with self.assertRaises(KeyError):
            list(self.project.find_job_documents())
        with self.assertRaises(KeyError):
            list(self.project.find_job_documents({'a': 0}))
        self.project.open_job({'a': 1}).document['statepoint'] = True
        with self.assertRaises(KeyError):
            list(self.project.find_job_documents())
        with self.assertRaises(KeyError):
            list(self.project.find_job_documents({'a': 1}))
        list(self.project.find_job_documents({'a': 2}))  # should not throw

    def test_repair_corrupted_workspace(self):
        statepoints = [{'a': i} for i in range(5)]
        for sp in statepoints:
            self.project.open_job(sp).document['test'] = True
        # no manifest file
        with self.project.open_job(statepoints[0]) as job:
            os.remove(job.FN_MANIFEST)
        # blank manifest file
        with self.project.open_job(statepoints[1]) as job:
            with open(job.FN_MANIFEST, 'w'):
                pass
        # Implement logging temporarily
        try:
            logging.disable(logging.CRITICAL)
            with self.assertRaises(ValueError):
                for i, statepoint in enumerate(self.project.find_statepoints()):
                    pass
            # The skip_errors function helps to identify corrupt directories.
            for i, statepoint in enumerate(self.project.find_statepoints(
                    skip_errors=True)):
                pass
            with self.assertRaises(RuntimeWarning):
                self.project.repair()
            self.project.write_statepoints(statepoints)
            self.project.repair()
            for i, statepoint in enumerate(self.project.find_statepoints()):
                pass
        finally:
            logging.disable(logging.NOTSET)

if __name__ == '__main__':
    unittest.main()
<commit_msg>Add unit test for index() method.<commit_after>import unittest
import os
import uuid
import warnings
import logging

import signac
from signac.common import six
from signac.contrib.formats import TextFile

from test_job import BaseJobTest

if six.PY2:
    logging.basicConfig(level=logging.WARNING)

# Make sure the jobs created for this test are unique.
test_token = {'test_token': str(uuid.uuid4())}

warnings.simplefilter('default')
warnings.filterwarnings('error', category=DeprecationWarning, module='signac')

class BaseProjectTest(BaseJobTest):
    pass

class ProjectTest(BaseProjectTest):

    def test_get(self):
        pass

    def test_get_id(self):
        self.assertEqual(self.project.get_id(), self.config['project'])
        self.assertEqual(str(self.project), self.project.get_id())

    def test_root_directory(self):
        self.assertEqual(self._tmp_pr, self.project.root_directory())

    def test_workspace_directory(self):
        self.assertEqual(self._tmp_wd, self.project.workspace())

    def test_workspace_directory_with_env_variable(self):
        os.environ['SIGNAC_ENV_DIR_TEST'] = self._tmp_wd
        self.project.config['workspace_dir'] = '${SIGNAC_ENV_DIR_TEST}'
        self.assertEqual(self._tmp_wd, self.project.workspace())

    def test_write_read_statepoint(self):
        statepoints = [{'a': i} for i in range(5)]
        self.project.dump_statepoints(statepoints)
        self.project.write_statepoints(statepoints)
        read = list(self.project.read_statepoints().values())
        self.assertEqual(len(read), len(statepoints))
        more_statepoints = [{'b': i} for i in range(5, 10)]
        self.project.write_statepoints(more_statepoints)
        read2 = list(self.project.read_statepoints())
        self.assertEqual(len(read2), len(statepoints) + len(more_statepoints))
        for id_ in self.project.read_statepoints().keys():
            self.project.get_statepoint(id_)

    def test_find_statepoints(self):
        statepoints = [{'a': i} for i in range(5)]
        for sp in statepoints:
            self.project.open_job(sp).init()
        self.assertEqual(
            len(statepoints),
            len(list(self.project.find_statepoints())))
        self.assertEqual(
            1, len(list(self.project.find_statepoints({'a': 0}))))

    def test_find_statepoint_sequences(self):
        statepoints = [{'a': (i, i+1)} for i in range(5)]
        for sp in statepoints:
            self.project.open_job(sp).init()
        self.assertEqual(
            len(statepoints),
            len(list(self.project.find_statepoints())))
        self.assertEqual(
            1,
            len(list(self.project.find_statepoints({'a': [0, 1]}))))
        self.assertEqual(
            1,
            len(list(self.project.find_statepoints({'a': (0, 1)}))))

    def test_find_jobs(self):
        statepoints = [{'a': i} for i in range(5)]
        for sp in statepoints:
            self.project.open_job(sp).document['test'] = True
        self.assertEqual(len(statepoints), len(list(self.project.find_jobs())))
        self.assertEqual(1, len(list(self.project.find_jobs({'a': 0}))))
        self.assertEqual(0, len(list(self.project.find_jobs({'a': 5}))))

    def test_num_jobs(self):
        statepoints = [{'a': i} for i in range(5)]
        for sp in statepoints:
            self.project.open_job(sp).init()
        self.assertEqual(len(statepoints), self.project.num_jobs())
        self.assertEqual(len(statepoints), len(list(self.project.find_jobs())))

    def test_open_job_by_id(self):
        statepoints = [{'a': i} for i in range(5)]
        jobs = [self.project.open_job(sp) for sp in statepoints]
        try:
            logging.disable(logging.WARNING)
            for job in jobs:
                with self.assertRaises(KeyError):
                    self.project.open_job(id=str(job))
            for job in jobs:
                job.init()
            for job in jobs:
                self.project.open_job(id=str(job))
            with self.assertRaises(KeyError):
                self.project.open_job(id='abc')
            with self.assertRaises(ValueError):
                self.project.open_job()
            with self.assertRaises(ValueError):
                self.project.open_job(statepoints[0], id=str(jobs[0]))
        finally:
            logging.disable(logging.NOTSET)

    def test_create_view(self):
        # Test for highly heterogenous parameter space
        sp_0 = [{'a': i, 'b': 0} for i in range(5)]
        sp_1 = [{'a': i, 'b': 0, 'c': {'a': i, 'b': 0}} for i in range(5)]
        sp_2 = [{'a': i, 'b': 0, 'c': {'a': i, 'b': 0, 'c': {'a': i, 'b': 0}}}
                for i in range(5)]
        statepoints = sp_0 + sp_1 + sp_2
        for sp in statepoints:
            self.project.open_job(sp).document['test'] = True
        key_set = list(signac.contrib.project._find_unique_keys(statepoints))
        self.assertEqual(len(statepoints), len(
            list(signac.contrib.project._make_urls(statepoints, key_set))))
        view_prefix = os.path.join(self._tmp_pr, 'view')
        self.project.create_view(prefix=view_prefix)
        self.assertTrue(os.path.isdir(view_prefix))

    def test_find_job_documents(self):
        statepoints = [{'a': i} for i in range(5)]
        for sp in statepoints:
            self.project.open_job(sp).document['test'] = True
        self.assertEqual(
            len(list(self.project.find_job_documents({'a': 0}))), 1)
        job_docs = list(self.project.find_job_documents())
        self.assertEqual(len(statepoints), len(job_docs))
        for job_doc in job_docs:
            sp = job_doc['statepoint']
            self.assertEqual(str(self.project.open_job(sp)), job_doc['_id'])

    def test_find_job_documents_illegal_key(self):
        statepoints = [{'a': i} for i in range(5)]
        for sp in statepoints:
            self.project.open_job(sp).document['test'] = True
        list(self.project.find_job_documents())
        self.assertEqual(len(statepoints), len(
            list(self.project.find_job_documents())))
        self.project.open_job({'a': 0}).document['_id'] = True
        list(self.project.find_job_documents({'a': 1}))  # should not throw
        with self.assertRaises(KeyError):
            list(self.project.find_job_documents())
        with self.assertRaises(KeyError):
            list(self.project.find_job_documents({'a': 0}))
        self.project.open_job({'a': 1}).document['statepoint'] = True
        with self.assertRaises(KeyError):
            list(self.project.find_job_documents())
        with self.assertRaises(KeyError):
            list(self.project.find_job_documents({'a': 1}))
        list(self.project.find_job_documents({'a': 2}))  # should not throw

    def test_repair_corrupted_workspace(self):
        statepoints = [{'a': i} for i in range(5)]
        for sp in statepoints:
            self.project.open_job(sp).document['test'] = True
        # no manifest file
        with self.project.open_job(statepoints[0]) as job:
            os.remove(job.FN_MANIFEST)
        # blank manifest file
        with self.project.open_job(statepoints[1]) as job:
            with open(job.FN_MANIFEST, 'w'):
                pass
        # Implement logging temporarily
        try:
            logging.disable(logging.CRITICAL)
            with self.assertRaises(ValueError):
                for i, statepoint in enumerate(self.project.find_statepoints()):
                    pass
            # The skip_errors function helps to identify corrupt directories.
            for i, statepoint in enumerate(self.project.find_statepoints(
                    skip_errors=True)):
                pass
            with self.assertRaises(RuntimeWarning):
                self.project.repair()
            self.project.write_statepoints(statepoints)
            self.project.repair()
            for i, statepoint in enumerate(self.project.find_statepoints()):
                pass
        finally:
            logging.disable(logging.NOTSET)

    def test_index(self):
        statepoints = [{'a': i} for i in range(5)]
        for sp in statepoints:
            self.project.open_job(sp).document['test'] = True
        job_ids = set((job.get_id() for job in self.project.find_jobs()))
        docs = list(self.project.index())
        job_ids_cmp = set((_id for _id, doc in docs))
        self.assertEqual(job_ids, job_ids_cmp)
        self.assertEqual(len(docs), len(statepoints))
        for sp in statepoints:
            with self.project.open_job(sp):
                with open('test.txt', 'w'):
                    pass
        docs = list(self.project.index({'.*/test.txt': TextFile}))
        self.assertEqual(len(docs), 2 * len(statepoints))
        self.assertEqual(len(set((_id for _id, _ in docs))), len(docs))

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


<commit_before>import os
import sys

import numpy as np

import fiedler

def filename_parse(fn, filter_min=.001,col=2,filter_col=2):
    """Wraps file_parse and infers paramaters based on extensions.

    Takes:
    filename.

    ".out" files will be treated as rf-ace output and filtered by imortance

    all other files will be treated as sif files.

    returns:
    The same tuple as filename_parse
    """

    fo = open(fn)
    out = ()

    out = fiedler.file_parse(fo, node2=1, filter_col=filter_col, filter_min=filter_min, val_col=col)

    fo.close()
    return out

def MDS(adj_list,plot=False,fn="FiedlerPlots",n_fied=2):
    (A,adj,Npts) = fiedler.adj_mat(adj_list)
    D = A.todense()

    #converting to distance...may not work for importance scores
    D = np.sqrt(1-np.abs(D))

    #from Ryan Tasseff's cmdsAnalysis
    [n,m] = D.shape
    eps = 1E-21
    if n!=m:
        raise ValueError('Wrong size matrix')

    # Construct an n x n centering matrix
    # The form is P = I - (1/n) U where U is a matrix of all ones
    P = np.eye(n) - (1/float(n) * np.ones((n,n)))
    # center the data
    B = np.dot(np.dot(P,-.5*D**2),P)
    # if len(w)>0:
    #     W = np.diag(np.sqrt(w))
    #     B = np.dot(np.dot(W,B),W)

    # Calculate the eigenvalues/vectors
    [E, V] = linalg.eig((B+B.T)/2) # may help with round off error??
    E = np.real(E) # these come out as complex but imaginary part should b ~eps
    V = np.real(V) # same as above
    # if len(w)>0:
    #     W = np.diag(1/np.sqrt(w))
    #     V = np.dot(W,V)
    # sort that mo fo
    ind = np.argsort(E)[::-1]
    E = E[ind]
    V = V[:,ind]
    # lets now create our return matrix
    if np.sum(E>eps)==0:
        Y = 0
    else:
        Y = V[:,E>eps]*np.sqrt(E[E>eps])
    return {"m1":list(Y[:,0], "m2":Y[:,1]}
    #return(Y,E)

def main():
    fn = sys.argv[1]
    filter_min = ""

    filter_min = float(sys.argv[2])

    col = int(sys.argv[3])
    filter_col = col
    if len(sys.argv)>4:
        filter_col=int(sys.argv[4])

    (adj_list, iByn, nByi) = filename_parse(fn, filter_min, col, filter_col)
    fn = os.path.basename(fn)
    fied = MDS(adj_list, fn=fn + str(filter_min), plot=False, n_fied=2)
    fied["adj"] = adj_list
    fied["iByn"] = iByn
    fied["nByi"] = nByi
    fo = open(os.path.basename(fn) +".cutoff."+ str(filter_min) + ".json", "w")
    json.dump(fied, fo)
    fo.close()<commit_msg>MDS syntax fix<commit_after>import os
import sys

import numpy as np

import fiedler

def filename_parse(fn, filter_min=.001,col=2,filter_col=2):
    """Wraps file_parse and infers paramaters based on extensions.

    Takes:
    filename.

    ".out" files will be treated as rf-ace output and filtered by imortance

    all other files will be treated as sif files.

    returns:
    The same tuple as filename_parse
    """

    fo = open(fn)
    out = ()

    out = fiedler.file_parse(fo, node2=1, filter_col=filter_col, filter_min=filter_min, val_col=col)

    fo.close()
    return out

def MDS(adj_list,plot=False,fn="FiedlerPlots",n_fied=2):
    (A,adj,Npts) = fiedler.adj_mat(adj_list)
    D = A.todense()

    #converting to distance...may not work for importance scores
    D = np.sqrt(1-np.abs(D))

    #from Ryan Tasseff's cmdsAnalysis
    [n,m] = D.shape
    eps = 1E-21
    if n!=m:
        raise ValueError('Wrong size matrix')

    # Construct an n x n centering matrix
    # The form is P = I - (1/n) U where U is a matrix of all ones
    P = np.eye(n) - (1/float(n) * np.ones((n,n)))
    # center the data
    B = np.dot(np.dot(P,-.5*D**2),P)
    # if len(w)>0:
    #     W = np.diag(np.sqrt(w))
    #     B = np.dot(np.dot(W,B),W)

    # Calculate the eigenvalues/vectors
    [E, V] = linalg.eig((B+B.T)/2) # may help with round off error??
    E = np.real(E) # these come out as complex but imaginary part should b ~eps
    V = np.real(V) # same as above
    # if len(w)>0:
    #     W = np.diag(1/np.sqrt(w))
    #     V = np.dot(W,V)
    # sort that mo fo
    ind = np.argsort(E)[::-1]
    E = E[ind]
    V = V[:,ind]
    # lets now create our return matrix
    if np.sum(E>eps)==0:
        Y = 0
    else:
        Y = V[:,E>eps]*np.sqrt(E[E>eps])
    return {"m1":list(Y[:,0]), "m2":list(Y[:,1])}
    #return(Y,E)

def main():
    fn = sys.argv[1]
    filter_min = ""

    filter_min = float(sys.argv[2])

    col = int(sys.argv[3])
    filter_col = col
    if len(sys.argv)>4:
        filter_col=int(sys.argv[4])

    (adj_list, iByn, nByi) = filename_parse(fn, filter_min, col, filter_col)
    fn = os.path.basename(fn)
    fied = MDS(adj_list, fn=fn + str(filter_min), plot=False, n_fied=2)
    fied["adj"] = adj_list
    fied["iByn"] = iByn
    fied["nByi"] = nByi
    fo = open(os.path.basename(fn) +".cutoff."+ str(filter_min) + ".json", "w")
    json.dump(fied, fo)
    fo.close()<|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

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, ['Linux', 'Hacker News'])

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('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('Apple', num_users=1, score_sum=1)

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

    paul.answer_correct(EASY_Q)
    assert_team_score('Apple', num_users=2, score_sum=1)  # paul is not in Apple team
    assert_team_score('Linux', num_users=1, score_sum=1)
    assert_team_score('Hacker News', num_users=1, score_sum=1)

    steve.answer_correct(MEDIUM_Q)
    assert_team_score('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 'Apple is your team' 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>Use TEAM_* constants instead of string literals in tests<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 = '/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
<|endoftext|>


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

# Hive Netius System
# Copyright (c) 2008-2017 Hive Solutions Lda.
#
# This file is part of Hive Netius System.
#
# Hive Netius System is free software: you can redistribute it and/or modify
# it under the terms of the Apache License as published by the Apache
# Foundation, either version 2.0 of the License, or (at your option) any
# later version.
#
# Hive Netius System is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# Apache License for more details.
#
# You should have received a copy of the Apache License along with
# Hive Netius System. If not, see <http://www.apache.org/licenses/>.

__author__ = "João Magalhães <joamag@hive.pt>"
""" The author(s) of the module """

__version__ = "1.0.0"
""" The version of the module """

__revision__ = "$LastChangedRevision$"
""" The revision number of the module """

__date__ = "$LastChangedDate$"
""" The last change date of the module """

__copyright__ = "Copyright (c) 2008-2017 Hive Solutions Lda."
""" The copyright for the module """

__license__ = "Apache License, Version 2.0"
""" The license for the module """

import struct

import netius

from . import util
from . import parser

IPV4 = 0x01

IPV6 = 0x04

DOMAIN = 0x03

VERSION_STATE = 1

HEADER_STATE = 2

USER_ID_STATE = 3

DOMAIN_STATE = 4

AUTH_COUNT_STATE = 5

AUTH_METHODS_STATE = 6

HEADER_EXTRA_STATE = 7

SIZE_STATE = 8

ADDRESS_STATE = 9

PORT_STATE = 10

FINISH_STATE = 11

class SOCKSParser(parser.Parser):

    def __init__(self, owner):
        parser.Parser.__init__(self, owner)

        self.build()
        self.reset()

    def build(self):
        """
        Builds the initial set of states ordered according to
        their internal integer definitions, this method provides
        a fast and scalable way of parsing data.
        """

        parser.Parser.build(self)

        self.states = (
            self._parse_version,
            self._parse_header,
            self._parse_user_id,
            self._parse_domain,
            self._parse_auth_count,
            self._parse_auth_methods,
            self._parse_header_extra,
            self._parse_size,
            self._parse_address,
            self._parse_port
        )
        self.state_l = len(self.states)

    def destroy(self):
        """
        Destroys the current structure for the parser meaning that
        it's restored to the original values, this method should only
        be called on situation where no more parser usage is required.
        """

        parser.Parser.destroy(self)

        self.states = ()
        self.state_l = 0

    def reset(self):
        self.state = VERSION_STATE
        self.buffer = []
        self.version = None
        self.command = None
        self.port = None
        self.address = None
        self.address_s = None
        self.user_id = None
        self.domain = None
        self.type = None
        self.size = 0
        self.is_extended = False
        self.auth_count = 0
        self.auth_methods = None

    def clear(self, force = False):
        if not force and self.state == VERSION_STATE: return
        self.reset()

    def parse(self, data):
        """
        Parses the provided data chunk, changing the current
        state of the parser accordingly and returning the
        number of processed bytes from it.

        :type data: String
        :param data: The string containing the data to be parsed
        in the current parse operation.
        :rtype: int
        :return: The amount of bytes of the data string that have
        been "parsed" in the current parse operation.
        """

        parser.Parser.parse(self, data)

        # in case the current state of the parser is finished, must
        # reset the state to the start position as the parser is
        # re-starting (probably a new data sequence)
        if self.state == FINISH_STATE: self.clear()

        # retrieves the size of the data that has been sent for parsing
        # and saves it under the size original variable
        size = len(data)
        size_o = size

        # iterates continuously to try to process all that
        # data that has been sent for processing
        while size > 0:

            if self.state <= self.state_l:
                method = self.states[self.state - 1]
                count = method(data)
                if count == 0: break

                size -= count
                data = data[count:]

                continue

            elif self.state == FINISH_STATE:
                break

            else:
                raise netius.ParserError("Invalid state '%d'" % self.state)

        # in case not all of the data has been processed
        # must add it to the buffer so that it may be used
        # latter in the next parsing of the message
        if size > 0: self.buffer.append(data)

        # returns the number of read (processed) bytes of the
        # data that has been sent to the parser
        return size_o - size

    def get_host(self):
        return self.domain or self.address_s

    def get_address(self):
        if self.type == None: return None

        if self.type == IPV4: address = struct.pack("!I", self.address)
        elif self.type == IPV6: address = struct.pack("!QQ", self.address)
        else: address = struct.pack("!B", self.size) + self.address

        return address

    def _parse_version(self, data):
        if len(data) < 1:
            raise netius.ParserError("Invalid request (too short)")

        request = data[:1]
        self.version, = struct.unpack("!B", request)

        if self.version == 4: self.state = HEADER_STATE
        elif self.version == 5: self.state = AUTH_COUNT_STATE
        else: raise netius.ParserError("Invalid version '%d'" % self.version)

        return 1

    def _parse_header(self, data):
        if len(data) < 7:
            raise netius.ParserError("Invalid request (too short)")

        request = data[:7]
        self.command, self.port, self.address = struct.unpack("!BHI", request)
        self.address_s = util.addr_to_ip4(self.address)

        self.is_extended = self.address_s.startswith("0.0.0.")

        self.state = USER_ID_STATE

        return 7

    def _parse_user_id(self, data):
        index = data.find(b"\0")
        if index == -1: return 0

        self.buffer.append(data[:index])
        self.user_id = b"".join(self.buffer)
        self.user_id = netius.legacy.str(self.user_id)
        del self.buffer[:]

        if self.is_extended: self.state = DOMAIN_STATE
        else: self.state = FINISH_STATE

        if not self.is_extended: self.trigger("on_data")
        return index + 1

    def _parse_domain(self, data):
        index = data.find(b"\0")
        if index == -1: return 0

        self.buffer.append(data[:index])
        self.domain = b"".join(self.buffer)
        self.domain = netius.legacy.str(self.domain)
        del self.buffer[:]

        self.state = FINISH_STATE

        self.trigger("on_data")
        return index + 1

    def _parse_auth_count(self, data):
        if len(data) < 1:
            raise netius.ParserError("Invalid request (too short)")

        request = data[:1]
        self.auth_count, = struct.unpack("!B", request)

        self.state = AUTH_METHODS_STATE

        return 1

    def _parse_auth_methods(self, data):
        is_ready = len(data) + len(self.buffer) >= self.auth_count
        if not is_ready: return 0

        remaining = self.auth_count - len(self.buffer)
        self.buffer.append(data[:remaining])
        data = b"".join(self.buffer)

        format = "!%dB" % self.auth_count
        self.auth_methods = struct.unpack(format, data)
        del self.buffer[:]

        self.state = HEADER_EXTRA_STATE

        self.trigger("on_auth")
        return remaining

    def _parse_header_extra(self, data):
        if len(data) < 4:
            raise netius.ParserError("Invalid request (too short)")

        request = data[:4]
        self.version, self.command, _reserved, self.type =\
            struct.unpack("!BBBB", request)

        if self.type == IPV4: self.size = 4
        elif self.type == IPV6: self.size = 16

        if self.type == DOMAIN: self.state = SIZE_STATE
        else: self.state = ADDRESS_STATE

        return 4

    def _parse_size(self, data):
        if len(data) < 1:
            raise netius.ParserError("Invalid request (too short)")

        request = data[:1]
        self.size, = struct.unpack("!B", request)

        self.state = ADDRESS_STATE

        return 1

    def _parse_address(self, data):
        is_ready = len(data) + len(self.buffer) >= self.size
        if not is_ready: return 0

        remaining = self.size - len(self.buffer)
        self.buffer.append(data[:remaining])
        data = b"".join(self.buffer)

        if self.type == IPV4:
            self.address, = struct.unpack("!I", data)
            self.address_s = util.addr_to_ip4(self.address)
        elif self.type == IPV6:
            self.address = struct.unpack("!QQ", data)
            self.address_s = self.address
        else:
            self.address = netius.legacy.str(data)
            self.address_s = netius.legacy.str(data)

        self.state = PORT_STATE

        return remaining

    def _parse_port(self, data):
        if len(data) < 2:
            raise netius.ParserError("Invalid request (too short)")

        request = data[:2]
        self.port, = struct.unpack("!H", request)

        self.state = FINISH_STATE

        self.trigger("on_data")
        return 2
<commit_msg>better support for ipv6<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-

# Hive Netius System
# Copyright (c) 2008-2017 Hive Solutions Lda.
#
# This file is part of Hive Netius System.
#
# Hive Netius System is free software: you can redistribute it and/or modify
# it under the terms of the Apache License as published by the Apache
# Foundation, either version 2.0 of the License, or (at your option) any
# later version.
#
# Hive Netius System is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# Apache License for more details.
#
# You should have received a copy of the Apache License along with
# Hive Netius System. If not, see <http://www.apache.org/licenses/>.

__author__ = "João Magalhães <joamag@hive.pt>"
""" The author(s) of the module """

__version__ = "1.0.0"
""" The version of the module """

__revision__ = "$LastChangedRevision$"
""" The revision number of the module """

__date__ = "$LastChangedDate$"
""" The last change date of the module """

__copyright__ = "Copyright (c) 2008-2017 Hive Solutions Lda."
""" The copyright for the module """

__license__ = "Apache License, Version 2.0"
""" The license for the module """

import struct

import netius

from . import util
from . import parser

IPV4 = 0x01

IPV6 = 0x04

DOMAIN = 0x03

VERSION_STATE = 1

HEADER_STATE = 2

USER_ID_STATE = 3

DOMAIN_STATE = 4

AUTH_COUNT_STATE = 5

AUTH_METHODS_STATE = 6

HEADER_EXTRA_STATE = 7

SIZE_STATE = 8

ADDRESS_STATE = 9

PORT_STATE = 10

FINISH_STATE = 11

class SOCKSParser(parser.Parser):

    def __init__(self, owner):
        parser.Parser.__init__(self, owner)

        self.build()
        self.reset()

    def build(self):
        """
        Builds the initial set of states ordered according to
        their internal integer definitions, this method provides
        a fast and scalable way of parsing data.
        """

        parser.Parser.build(self)

        self.states = (
            self._parse_version,
            self._parse_header,
            self._parse_user_id,
            self._parse_domain,
            self._parse_auth_count,
            self._parse_auth_methods,
            self._parse_header_extra,
            self._parse_size,
            self._parse_address,
            self._parse_port
        )
        self.state_l = len(self.states)

    def destroy(self):
        """
        Destroys the current structure for the parser meaning that
        it's restored to the original values, this method should only
        be called on situation where no more parser usage is required.
        """

        parser.Parser.destroy(self)

        self.states = ()
        self.state_l = 0

    def reset(self):
        self.state = VERSION_STATE
        self.buffer = []
        self.version = None
        self.command = None
        self.port = None
        self.address = None
        self.address_s = None
        self.user_id = None
        self.domain = None
        self.type = None
        self.size = 0
        self.is_extended = False
        self.auth_count = 0
        self.auth_methods = None

    def clear(self, force = False):
        if not force and self.state == VERSION_STATE: return
        self.reset()

    def parse(self, data):
        """
        Parses the provided data chunk, changing the current
        state of the parser accordingly and returning the
        number of processed bytes from it.

        :type data: String
        :param data: The string containing the data to be parsed
        in the current parse operation.
        :rtype: int
        :return: The amount of bytes of the data string that have
        been "parsed" in the current parse operation.
        """

        parser.Parser.parse(self, data)

        # in case the current state of the parser is finished, must
        # reset the state to the start position as the parser is
        # re-starting (probably a new data sequence)
        if self.state == FINISH_STATE: self.clear()

        # retrieves the size of the data that has been sent for parsing
        # and saves it under the size original variable
        size = len(data)
        size_o = size

        # iterates continuously to try to process all that
        # data that has been sent for processing
        while size > 0:

            if self.state <= self.state_l:
                method = self.states[self.state - 1]
                count = method(data)
                if count == 0: break

                size -= count
                data = data[count:]

                continue

            elif self.state == FINISH_STATE:
                break

            else:
                raise netius.ParserError("Invalid state '%d'" % self.state)

        # in case not all of the data has been processed
        # must add it to the buffer so that it may be used
        # latter in the next parsing of the message
        if size > 0: self.buffer.append(data)

        # returns the number of read (processed) bytes of the
        # data that has been sent to the parser
        return size_o - size

    def get_host(self):
        return self.domain or self.address_s

    def get_address(self):
        if self.type == None: return None

        if self.type == IPV4: address = struct.pack("!I", self.address)
        elif self.type == IPV6: address = struct.pack("!QQ", self.address)
        else: address = struct.pack("!B", self.size) + self.address

        return address

    def _parse_version(self, data):
        if len(data) < 1:
            raise netius.ParserError("Invalid request (too short)")

        request = data[:1]
        self.version, = struct.unpack("!B", request)

        if self.version == 4: self.state = HEADER_STATE
        elif self.version == 5: self.state = AUTH_COUNT_STATE
        else: raise netius.ParserError("Invalid version '%d'" % self.version)

        return 1

    def _parse_header(self, data):
        if len(data) < 7:
            raise netius.ParserError("Invalid request (too short)")

        request = data[:7]
        self.command, self.port, self.address = struct.unpack("!BHI", request)
        self.address_s = util.addr_to_ip4(self.address)

        self.is_extended = self.address_s.startswith("0.0.0.")

        self.state = USER_ID_STATE

        return 7

    def _parse_user_id(self, data):
        index = data.find(b"\0")
        if index == -1: return 0

        self.buffer.append(data[:index])
        self.user_id = b"".join(self.buffer)
        self.user_id = netius.legacy.str(self.user_id)
        del self.buffer[:]

        if self.is_extended: self.state = DOMAIN_STATE
        else: self.state = FINISH_STATE

        if not self.is_extended: self.trigger("on_data")
        return index + 1

    def _parse_domain(self, data):
        index = data.find(b"\0")
        if index == -1: return 0

        self.buffer.append(data[:index])
        self.domain = b"".join(self.buffer)
        self.domain = netius.legacy.str(self.domain)
        del self.buffer[:]

        self.state = FINISH_STATE

        self.trigger("on_data")
        return index + 1

    def _parse_auth_count(self, data):
        if len(data) < 1:
            raise netius.ParserError("Invalid request (too short)")

        request = data[:1]
        self.auth_count, = struct.unpack("!B", request)

        self.state = AUTH_METHODS_STATE

        return 1

    def _parse_auth_methods(self, data):
        is_ready = len(data) + len(self.buffer) >= self.auth_count
        if not is_ready: return 0

        remaining = self.auth_count - len(self.buffer)
        self.buffer.append(data[:remaining])
        data = b"".join(self.buffer)

        format = "!%dB" % self.auth_count
        self.auth_methods = struct.unpack(format, data)
        del self.buffer[:]

        self.state = HEADER_EXTRA_STATE

        self.trigger("on_auth")
        return remaining

    def _parse_header_extra(self, data):
        if len(data) < 4:
            raise netius.ParserError("Invalid request (too short)")

        request = data[:4]
        self.version, self.command, _reserved, self.type =\
            struct.unpack("!BBBB", request)

        if self.type == IPV4: self.size = 4
        elif self.type == IPV6: self.size = 16

        if self.type == DOMAIN: self.state = SIZE_STATE
        else: self.state = ADDRESS_STATE

        return 4

    def _parse_size(self, data):
        if len(data) < 1:
            raise netius.ParserError("Invalid request (too short)")

        request = data[:1]
        self.size, = struct.unpack("!B", request)

        self.state = ADDRESS_STATE

        return 1

    def _parse_address(self, data):
        is_ready = len(data) + len(self.buffer) >= self.size
        if not is_ready: return 0

        remaining = self.size - len(self.buffer)
        self.buffer.append(data[:remaining])
        data = b"".join(self.buffer)

        if self.type == IPV4:
            self.address, = struct.unpack("!I", data)
            self.address_s = util.addr_to_ip4(self.address)
        elif self.type == IPV6:
            address_t = struct.unpack("!QQ", data)
            self.address = (address_t[0] << 64) + address_t[1]
            self.address_s = util.addr_to_ip6(self.address)
        else:
            self.address = netius.legacy.str(data)
            self.address_s = netius.legacy.str(data)

        self.state = PORT_STATE

        return remaining

    def _parse_port(self, data):
        if len(data) < 2:
            raise netius.ParserError("Invalid request (too short)")

        request = data[:2]
        self.port, = struct.unpack("!H", request)

        self.state = FINISH_STATE

        self.trigger("on_data")
        return 2
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
import mock
import pytest
from lxml import html

from ...helpers import LoggedInApplicationTest

@mock.patch('app.main.views.service_updates.data_api_client', autospec=True)
class TestServiceUpdates(LoggedInApplicationTest):
    user_role = 'admin-ccs-category'

    @pytest.mark.parametrize("role,expected_code", [
        ("admin", 403),
        ("admin-ccs-category", 200),
        ("admin-ccs-sourcing", 403),
        ("admin-manager", 403),
    ])
    def test_view_service_updates_only_for_allowed_user_roles(self, data_api_client, role, expected_code):
        self.user_role = role
        response = self.client.get('/admin/services/updates/unapproved')
        actual_code = response.status_code
        assert actual_code == expected_code, "Unexpected response {} for role {}".format(actual_code, role)

    @pytest.mark.parametrize('audit_events,expected_table_contents,expected_count', (
        (
            (
                ('2012-07-15T18:03:43.061077Z', '1123456789012351', u'Company name', '240697', '240680'),
                ('2016-03-05T10:42:16.061077Z', '1123456789012348', u'Testing Ltd', '240699', '240682'),
                ('2017-04-25T14:43:46.061077Z', '597637931594387', u'Making £ Inc', '240701', '240684'),
            ),
            (
                ('Company name', '1123456789012351', '15 July at 18:03:43', '/admin/services/1123456789012351/updates'),
                (u'Testing Ltd', '1123456789012348', '5 March at 10:42:16', '/admin/services/1123456789012348/updates'),
                (u'Making £ Inc', '597637931594387', '25 April at 14:43:46', '/admin/services/597637931594387/updates'),
            ),
            '3 edited services',
        ),
        (
            (
                ('2012-07-15T18:03:43.061077Z', '597637931590002', 'Company name', '240697', '240680'),
                ('2016-03-05T10:42:16.061077Z', '597637931590001', 'Ideal Health', '240699', '240682'),
            ),
            (
                ('Company name', '597637931590002', '15 July at 18:03:43', '/admin/services/597637931590002/updates'),
                ('Ideal Health', '597637931590001', '5 March at 10:42:16', '/admin/services/597637931590001/updates'),
            ),
            '2 edited services',
        ),
        (
            (),
            (),
            '0 edited services',
        ),
        (
            (
                ('2012-07-15T18:03:43.061077Z', '597637931590002', 'Company name', '240697', '240680'),
            ),
            (
                ('Company name', '597637931590002', '15 July at 18:03:43', '/admin/services/597637931590002/updates'),
            ),
            '1 edited service',
        ),
    ))
    def test_should_show_unacknowledged_services(
            self, data_api_client, audit_events, expected_table_contents, expected_count):
        data_api_client.find_audit_events.return_value = {
            "auditEvents": [
                {
                    "data": {
                        "oldArchivedServiceId": old_archived_service_id,
                        "newArchivedServiceId": new_archived_service_id,
                        "serviceId": service_id,
                        "supplierName": supplier_name,
                    },
                    "createdAt": date_string
                } for (
                    date_string, service_id, supplier_name, old_archived_service_id, new_archived_service_id
                ) in audit_events
            ],
            "links": {},
        }

        response = self.client.get('/admin/services/updates/unapproved')

        assert response.status_code == 200
        document = html.fromstring(response.get_data(as_text=True))

        assert tuple(
            tuple(
                td.xpath('normalize-space(string())') for td in tr.xpath('./td')[:-1]
            ) + (tr.xpath('./td[last()]//a/@href')[0],)
            for tr in document.xpath('//table[@class="summary-item-body"]/tbody/tr')
        ) == expected_table_contents

        assert document.xpath('normalize-space(string(//*[@class="search-summary"]))') == expected_count

        if audit_events != ():
            assert tuple(
                tuple(th.xpath('normalize-space(string())') for th in tr.xpath('./th'))
                for tr in document.xpath('//table[@class="summary-item-body"]/thead/tr')
            ) == (('Supplier', 'Service ID', 'Edited', 'Changes'),)

    def test_acknowledge_audit_event_happy_path(self, data_api_client):
        audit_event = {
            'auditEvents': {
                'acknowledged': False,
                'links': {
                    'self': 'http://localhost:5000/services/updates/unapproved'
                },
                'data': {
                    'serviceName': 'new name',
                    'supplierId': 93518,
                    'supplierName': 'Clouded Networks',
                    'serviceId': '321',
                },
                'user': 'joeblogs',
                'type': 'update_service',
                'id': 123,
                'createdAt': '2015-06-17T08:49:22.999Z'
            },
            'links': {}
        }

        data_api_client.get_audit_event.side_effect = lambda audit_event_id: {123: audit_event}[audit_event_id]
        response = self.client.post('/admin/services/321/updates/123/approve')
        assert response.status_code == 302
        self.assert_flashes("The changes to service 321 were approved.")
        assert response.location == 'http://localhost/admin/services/updates/unapproved'

        data_api_client.acknowledge_service_update_including_previous.assert_called_with(
            u'321',
            123,
            'test@example.com'
        )

    def test_should_404_wrong_service_id(self, data_api_client):
        response = self.client.post('/admin/services/123/updates/321/approve')
        assert response.status_code == 404

    @pytest.mark.parametrize("role_not_allowed", ["admin", "admin-ccs-sourcing", "admin-manager"])
    def test_post_should_403_forbidden_user_roles(self, data_api_client, role_not_allowed):
        self.user_role = role_not_allowed
        response = self.client.post('/admin/services/123/updates/321/approve')
        assert response.status_code == 403

    def test_should_410_already_acknowledged_event(self, data_api_client):
        audit_event = {
            'auditEvents': {
                'acknowledged': True,
                'links': {
                    'self': 'http://localhost:5000/audit-events'
                },
                'data': {
                    'serviceName': 'new name',
                    'supplierId': 93518,
                    'supplierName': 'Clouded Networks',
                    'serviceId': '321',
                },
                'user': 'joeblogs',
                'type': 'update_service',
                'id': 123,
                'createdAt': '2015-06-17T08:49:22.999Z'
            },
            'links': {}
        }

        data_api_client.get_audit_event.side_effect = lambda audit_event_id: {123: audit_event}[audit_event_id]
        response = self.client.post('/admin/services/321/updates/123/approve')
        assert response.status_code == 410

    def test_should_404_wrong_audit_event_type(self, data_api_client):
        audit_event = {
            'auditEvents': {
                'acknowledged': False,
                'links': {
                    'self': 'http://localhost:5000/audit-events'
                },
                'data': {
                    'serviceName': 'new name',
                    'supplierId': 93518,
                    'supplierName': 'Clouded Networks',
                    'serviceId': '321',
                },
                'user': 'joeblogs',
                'type': 'not_the_right_type',
                'id': 123,
                'createdAt': '2015-06-17T08:49:22.999Z'
            },
            'links': {}
        }

        data_api_client.get_audit_event.side_effect = lambda audit_event_id: {123: audit_event}[audit_event_id]
        response = self.client.post('/admin/services/321/updates/123/approve')
        assert response.status_code == 404
<commit_msg>Refactor TestServiceUpdates<commit_after># -*- coding: utf-8 -*-
import mock
import pytest
from lxml import html

from ...helpers import LoggedInApplicationTest

class TestServiceUpdates(LoggedInApplicationTest):
    user_role = 'admin-ccs-category'

    def setup_method(self, method):
        super().setup_method(method)
        self.data_api_client_patch = mock.patch('app.main.views.service_updates.data_api_client', autospec=True)
        self.data_api_client = self.data_api_client_patch.start()

    def teardown_method(self, method):
        self.data_api_client_patch.stop()
        super().teardown_method(method)

    @pytest.mark.parametrize("role,expected_code", [
        ("admin", 403),
        ("admin-ccs-category", 200),
        ("admin-ccs-sourcing", 403),
        ("admin-manager", 403),
    ])
    def test_view_service_updates_only_for_allowed_user_roles(self, role, expected_code):
        self.user_role = role
        response = self.client.get('/admin/services/updates/unapproved')
        actual_code = response.status_code
        assert actual_code == expected_code, "Unexpected response {} for role {}".format(actual_code, role)

    @pytest.mark.parametrize('audit_events,expected_table_contents,expected_count', (
        (
            (
                ('2012-07-15T18:03:43.061077Z', '1123456789012351', u'Company name', '240697', '240680'),
                ('2016-03-05T10:42:16.061077Z', '1123456789012348', u'Testing Ltd', '240699', '240682'),
                ('2017-04-25T14:43:46.061077Z', '597637931594387', u'Making £ Inc', '240701', '240684'),
            ),
            (
                ('Company name', '1123456789012351', '15 July at 18:03:43', '/admin/services/1123456789012351/updates'),
                (u'Testing Ltd', '1123456789012348', '5 March at 10:42:16', '/admin/services/1123456789012348/updates'),
                (u'Making £ Inc', '597637931594387', '25 April at 14:43:46', '/admin/services/597637931594387/updates'),
            ),
            '3 edited services',
        ),
        (
            (
                ('2012-07-15T18:03:43.061077Z', '597637931590002', 'Company name', '240697', '240680'),
                ('2016-03-05T10:42:16.061077Z', '597637931590001', 'Ideal Health', '240699', '240682'),
            ),
            (
                ('Company name', '597637931590002', '15 July at 18:03:43', '/admin/services/597637931590002/updates'),
                ('Ideal Health', '597637931590001', '5 March at 10:42:16', '/admin/services/597637931590001/updates'),
            ),
            '2 edited services',
        ),
        (
            (),
            (),
            '0 edited services',
        ),
        (
            (
                ('2012-07-15T18:03:43.061077Z', '597637931590002', 'Company name', '240697', '240680'),
            ),
            (
                ('Company name', '597637931590002', '15 July at 18:03:43', '/admin/services/597637931590002/updates'),
            ),
            '1 edited service',
        ),
    ))
    def test_should_show_unacknowledged_services(self, audit_events, expected_table_contents, expected_count):
        self.data_api_client.find_audit_events.return_value = {
            "auditEvents": [
                {
                    "data": {
                        "oldArchivedServiceId": old_archived_service_id,
                        "newArchivedServiceId": new_archived_service_id,
                        "serviceId": service_id,
                        "supplierName": supplier_name,
                    },
                    "createdAt": date_string
                } for (
                    date_string, service_id, supplier_name, old_archived_service_id, new_archived_service_id
                ) in audit_events
            ],
            "links": {},
        }

        response = self.client.get('/admin/services/updates/unapproved')

        assert response.status_code == 200
        document = html.fromstring(response.get_data(as_text=True))

        assert tuple(
            tuple(
                td.xpath('normalize-space(string())') for td in tr.xpath('./td')[:-1]
            ) + (tr.xpath('./td[last()]//a/@href')[0],)
            for tr in document.xpath('//table[@class="summary-item-body"]/tbody/tr')
        ) == expected_table_contents

        assert document.xpath('normalize-space(string(//*[@class="search-summary"]))') == expected_count

        if audit_events != ():
            assert tuple(
                tuple(th.xpath('normalize-space(string())') for th in tr.xpath('./th'))
                for tr in document.xpath('//table[@class="summary-item-body"]/thead/tr')
            ) == (('Supplier', 'Service ID', 'Edited', 'Changes'),)

    def test_acknowledge_audit_event_happy_path(self):
        audit_event = {
            'auditEvents': {
                'acknowledged': False,
                'links': {
                    'self': 'http://localhost:5000/services/updates/unapproved'
                },
                'data': {
                    'serviceName': 'new name',
                    'supplierId': 93518,
                    'supplierName': 'Clouded Networks',
                    'serviceId': '321',
                },
                'user': 'joeblogs',
                'type': 'update_service',
                'id': 123,
                'createdAt': '2015-06-17T08:49:22.999Z'
            },
            'links': {}
        }

        self.data_api_client.get_audit_event.side_effect = lambda audit_event_id: {123: audit_event}[audit_event_id]
        response = self.client.post('/admin/services/321/updates/123/approve')
        assert response.status_code == 302
        self.assert_flashes("The changes to service 321 were approved.")
        assert response.location == 'http://localhost/admin/services/updates/unapproved'

        self.data_api_client.acknowledge_service_update_including_previous.assert_called_with(
            u'321',
            123,
            'test@example.com'
        )

    def test_should_404_wrong_service_id(self):
        response = self.client.post('/admin/services/123/updates/321/approve')
        assert response.status_code == 404

    @pytest.mark.parametrize("role_not_allowed", ["admin", "admin-ccs-sourcing", "admin-manager"])
    def test_post_should_403_forbidden_user_roles(self, role_not_allowed):
        self.user_role = role_not_allowed
        response = self.client.post('/admin/services/123/updates/321/approve')
        assert response.status_code == 403

    def test_should_410_already_acknowledged_event(self):
        audit_event = {
            'auditEvents': {
                'acknowledged': True,
                'links': {
                    'self': 'http://localhost:5000/audit-events'
                },
                'data': {
                    'serviceName': 'new name',
                    'supplierId': 93518,
                    'supplierName': 'Clouded Networks',
                    'serviceId': '321',
                },
                'user': 'joeblogs',
                'type': 'update_service',
                'id': 123,
                'createdAt': '2015-06-17T08:49:22.999Z'
            },
            'links': {}
        }

        self.data_api_client.get_audit_event.side_effect = lambda audit_event_id: {123: audit_event}[audit_event_id]
        response = self.client.post('/admin/services/321/updates/123/approve')
        assert response.status_code == 410

    def test_should_404_wrong_audit_event_type(self):
        audit_event = {
            'auditEvents': {
                'acknowledged': False,
                'links': {
                    'self': 'http://localhost:5000/audit-events'
                },
                'data': {
                    'serviceName': 'new name',
                    'supplierId': 93518,
                    'supplierName': 'Clouded Networks',
                    'serviceId': '321',
                },
                'user': 'joeblogs',
                'type': 'not_the_right_type',
                'id': 123,
                'createdAt': '2015-06-17T08:49:22.999Z'
            },
            'links': {}
        }

        self.data_api_client.get_audit_event.side_effect = lambda audit_event_id: {123: audit_event}[audit_event_id]
        response = self.client.post('/admin/services/321/updates/123/approve')
        assert response.status_code == 404
<|endoftext|>


<commit_before>from kinematics_app import app
import os

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 5000))
    app.run(host='0.0.0.0', port=port, debug=True)<commit_msg>set debug to false<commit_after>from kinematics_app import app
import os

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 5000))
    app.run(host='0.0.0.0', port=port, debug=False)<|endoftext|>


<commit_before>#!/usr/bin/nenv python
# encoding: utf-8
"""
modelsTest.py

This file contains the tests for the various models

"""
import unittest

from google.appengine.ext import db

from testHarness import AppEngineTestCase as TestCase

from application import models

class FamilyModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class ContractModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class UserModelTestCase(TestCase):

    def testAttributes(self):
        # Check if attributes exist
        self.assertTrue(hasattr(models.User,'firstName'), 'User model has no firstName attribute')
        self.assertTrue(hasattr(models.User,'lastName'), 'User model has no lastName attribute')
        self.assertTrue(hasattr(models.User,'cwruID'), 'User model has no cwruID attribute')
        self.assertTrue(hasattr(models.User,'salt'), 'User model has no salt attribute')
        self.assertTrue(hasattr(models.User,'hash'), 'User model has no hash attribute')
        self.assertTrue(hasattr(models.User,'middleName'), 'User model has no middleName attribute')
        self.assertTrue(hasattr(models.User,'contractType'), 'User model has no contractType attribute')
        self.assertTrue(hasattr(models.User,'family'), 'User model has no family attribute')
        self.assertTrue(hasattr(models.User,'big'), 'User model has no big attribute')
        self.assertTrue(hasattr(models.User,'avatar'), 'User model has no avatar attribute')

        # Check if required attributes are required
        self.assertTrue(models.User.firstName.required, 'User.firstName should be required')
        self.assertTrue(models.User.lastName.required, 'User.lastName should be required')
        self.assertTrue(models.User.cwruID.required, 'User.cwruID should be required')
        self.assertTrue(models.User.salt.required, 'User.salt should be required')
        self.assertTrue(models.User.hash.required, 'User.hash should be required')

        # Check if optional attributes are optional
        self.assertFalse(models.User.middleName.required, 'User.middleName should be optional')
        self.assertFalse(models.User.contractType.required, 'User.contractType should be optional')
        self.assertFalse(models.User.family.required, 'User.family should be optional')
        self.assertFalse(models.User.big.required, 'User.big should be optional')
        self.assertFalse(models.User.avatar.required, 'User.avatar should be optional')

class RoleModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class UserRoleModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class AddressModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class EmailModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class PhoneNumberModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class EventModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class LocationModelTestCase(TestCase):

    def testAttributes(self):
        pass

class ServiceEventModelTestCase(TestCase):
    def testAttributes(self):
        self.fail('Not implemented!')

class ServiceSignUpModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class InsideServiceReportModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class OutsideServiceReportModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class ServiceHourModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class ChapterEventModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class RequirementModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class HourReqModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class DuesReqModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class AttendanceModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class PostModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class CommentModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

if __name__ == '__main__':
    unittest.main()
        <commit_msg>Updated and added more tests for the models<commit_after>#!/usr/bin/nenv python
# encoding: utf-8
"""
modelsTest.py

This file contains the tests for the various models

"""
import unittest

from google.appengine.ext import db

from testHarness import AppEngineTestCase as TestCase

from application import models

class FamilyModelTestCase(TestCase):

    def testAttributes(self):
        # Check if attributes exist
        self.assertTrue(hasattr(models.Family, 'name'), 'Family model has no name attribute')

        # Check type of attributes
        self.assertTrue(isinstance(models.Family.name, db.StringProperty), 'Family.name should be a unicode string')

        # Check if required attributes are required
        self.assertTrue(models.Family.name.required, 'Family.name should be required')

class ContractModelTestCase(TestCase):

    def testAttributes(self):
        # Check if attributes exist
        self.assertTrue(hasattr(models.Contract, 'name'), 'Contract model has no name attribute')

        # Check type of attributes
        self.assertTrue(isinstance(models.Contract.name, db.StringProperty), 'Contract.name should be a unicode string')

        # Check if required attributes are required
        self.assertTrue(models.Contract.name.required, 'Contract.name should be required')

class UserModelTestCase(TestCase):

    def testAttributes(self):
        # Check if attributes exist
        self.assertTrue(hasattr(models.User,'firstName'), 'User model has no firstName attribute')
        self.assertTrue(hasattr(models.User,'lastName'), 'User model has no lastName attribute')
        self.assertTrue(hasattr(models.User,'cwruID'), 'User model has no cwruID attribute')
        self.assertTrue(hasattr(models.User,'salt'), 'User model has no salt attribute')
        self.assertTrue(hasattr(models.User,'hash'), 'User model has no hash attribute')
        self.assertTrue(hasattr(models.User,'middleName'), 'User model has no middleName attribute')
        self.assertTrue(hasattr(models.User,'contractType'), 'User model has no contractType attribute')
        self.assertTrue(hasattr(models.User,'family'), 'User model has no family attribute')
        self.assertTrue(hasattr(models.User,'big'), 'User model has no big attribute')
        self.assertTrue(hasattr(models.User,'avatar'), 'User model has no avatar attribute')

        # Check type of attributes
        self.assertTrue(isinstance(models.User.firstName, db.StringProperty), 'User.firstName should be a unicode string')
        self.assertTrue(isinstance(models.User.lastName, db.StringProperty), 'User.lastName should be a unicode string')
        self.assertTrue(isinstance(models.User.cwruID, db.StringProperty), 'User.cwruID should be a unicode string')
        self.assertTrue(isinstance(models.User.salt, db.StringProperty), 'User.salt should be a unicode string')
        self.assertTrue(isinstance(models.User.hash, db.StringProperty), 'User.hash should be a unicode string')
        self.assertTrue(isinstance(models.User.middleName, db.StringProperty), 'User.middleName should be a unicode string')
        self.assertTrue(isinstance(models.User.contractType, db.ReferenceProperty), 'User.contractType should be a reference to a Contract entity')
        self.assertTrue(isinstance(models.User.family, db.ReferenceProperty), 'User.family should be a reference to a Family entity')
        self.assertTrue(isinstance(models.User.big, db.ReferenceProperty), 'User.big should be a self reference')
        self.assertTrue(isinstance(models.User.avatar, db.StringProperty), 'User.avatar should be a unicode string')

        # Check if required attributes are required
        self.assertTrue(models.User.firstName.required, 'User.firstName should be required')
        self.assertTrue(models.User.lastName.required, 'User.lastName should be required')
        self.assertTrue(models.User.cwruID.required, 'User.cwruID should be required')
        self.assertTrue(models.User.salt.required, 'User.salt should be required')
        self.assertTrue(models.User.hash.required, 'User.hash should be required')

        # Check if optional attributes are optional
        self.assertFalse(models.User.middleName.required, 'User.middleName should be optional')
        self.assertFalse(models.User.contractType.required, 'User.contractType should be optional')
        self.assertFalse(models.User.family.required, 'User.family should be optional')
        self.assertFalse(models.User.big.required, 'User.big should be optional')
        self.assertFalse(models.User.avatar.required, 'User.avatar should be optional')

class RoleModelTestCase(TestCase):

    def testAttributes(self):
        # Check if attributes exist
        self.assertTrue(hasattr(models.Role, 'name'), 'Role model has no name attribute')
        self.assertTrue(hasattr(models.Role, 'desc'), 'Role model has no desc attribute')

        # Check if attributes are correct type
        self.assertTrue(isinstance(models.Role.name, db.StringProperty), 'Role.name should be a unicode string')
        self.assertTrue(isinstance(models.Role.desc, db.StringProperty), 'Role.desc should be a unicode string')

        # Check if required attributes are required
        self.assertTrue(models.Role.name.required, 'Role.name should be required')

        # Check if optional attributes are optional
        self.assertFalse(models.Role.desc.required, 'Role.desc should be optional')

class UserRoleModelTestCase(TestCase):

    def testAttributes(self):
        # Check if attributes exist
        self.assertTrue(hasattr(models.UserRole, 'user'), 'UserRole model has no user attribute')
        self.assertTrue(hasattr(models.UserRole, 'role'), 'UserRole model has no role attribute')

        # Check if attributes are correct type
        self.assertTrue(isinstance(models.UserRole.user, db.ReferenceProperty), 'UserRole.user should be a reference to a User entity')
        self.assertTrue(isinstance(models.UserRole.role, db.ReferenceProperty), 'UserRole.role should be a reference to a Role entity')

        # Check if required attributes are required
        self.assertTrue(models.UserRole.user.required, 'UserRole.user should be required')
        self.assertTrue(models.UserRole.role.required, 'UserRole.role should be required')

class AddressModelTestCase(TestCase):

    def testAttributes(self):
        # Check if attributes exist
        self.assertTrue(hasattr(models.Address, 'user'), 'Address model has no user attribute')
        self.assertTrue(hasattr(models.Address, 'address'), 'Address model has no address attribute')
        self.assertTrue(hasattr(models.Address, 'name'), 'Address model has no name attribute')

        # Check if attributes are correct type
        self.assertTrue(isinstance(models.Address.user, db.ReferenceProperty), 'Address.user should be a reference to a User entity')
        self.assertTrue(isinstance(models.Address.address, db.PostalAddressProperty), 'Address.address should be a PostalAddress entity')
        self.assertTrue(isinstance(models.Address.name, db.StringProperty), 'Address.name should be a unicode string')

        # Check if required attributes are required
        self.assertTrue(models.Address.user.required, 'Address.user should be required')
        self.assertTrue(models.Address.address.required, 'Address.address should be required')

        # Check if optional attributes are optional
        self.assertFalse(models.Address.name.required, 'Address.name should be optional')

class EmailModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class PhoneNumberModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class EventModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class LocationModelTestCase(TestCase):

    def testAttributes(self):
        pass

class ServiceEventModelTestCase(TestCase):
    def testAttributes(self):
        self.fail('Not implemented!')

class ServiceSignUpModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class InsideServiceReportModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class OutsideServiceReportModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class ServiceHourModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class ChapterEventModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class RequirementModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class HourReqModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class DuesReqModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class AttendanceModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class PostModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

class CommentModelTestCase(TestCase):

    def testAttributes(self):
        self.fail('Not Implemented!')

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