Skip to content

Commit

Permalink
Added tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
rmax committed Jun 23, 2016
1 parent 85e9c43 commit 23423f5
Show file tree
Hide file tree
Showing 7 changed files with 241 additions and 8 deletions.
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,15 @@ clean-cython:
lint:
flake8 src tests

build-inplace:
python setup.py build_ext --inplace
python setup_tests.py build_ext --inplace

develop: clean
python setup.py develop -v

test: develop
python setup_tests.py build_ext --inplace
py.test -v

test-all:
Expand Down
4 changes: 4 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ tag = True
search = version='{current_version}'
replace = version='{new_version}'

[bumpversion:file:setup_tests.py]
search = version='{current_version}'
replace = version='{new_version}'

[bumpversion:file:src/yammh3/__init__.py]
search = __version__ = '{current_version}'
replace = __version__ = '{new_version}'
Expand Down
31 changes: 31 additions & 0 deletions setup_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys

from setuptools import setup
from setuptools.extension import Extension

from Cython.Build import cythonize

import yammh3


def get_extensions():
kwargs = {
'include_dirs': [yammh3.get_include()],
}
return cythonize([
Extension('tests._test_cimports', ['tests/_test_cimports.pyx'], **kwargs),
])


setup(
name='yammh3-tests',
version='0.1.0',
packages=['tests'],
package_data={
"tests": ['*.pyx', '*.pxd'],
},
ext_modules=get_extensions(),
)
25 changes: 25 additions & 0 deletions tests/_test_cimports.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from yammh3._yammh3 cimport (
mhash128, mhash128s,
mhash128_x64, mhash128s_x64,
mhash64, mhash64s, mhash64l, mhash64sl,
mhash64_x64, mhash64s_x64, mhash64l_x64, mhash64sl_x64,
mhash32, mhash32s,
)


def test_cimports(bytes s, int n):
mhash128(s, n)
mhash128(s, n)
mhash128s(s, n)
mhash128_x64(s, n)
mhash128s_x64(s, n)
mhash64(s, n)
mhash64s(s, n)
mhash64l(s, n)
mhash64sl(s, n)
mhash64_x64(s, n)
mhash64s_x64(s, n)
mhash64l_x64(s, n)
mhash64sl_x64(s, n)
mhash32(s, n)
mhash32s(s, n)
9 changes: 9 additions & 0 deletions tests/test_cimports.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from hypothesis import given, strategies as st

from ._test_cimports import test_cimports as _test_cimports


@given(st.text())
def test_cimports(value):
b_value = value.encode('utf-8')
_test_cimports(b_value, len(b_value))
166 changes: 160 additions & 6 deletions tests/test_yammh3.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,169 @@
Tests for `yammh3` module.
"""
import functools
import glob
import os
import pytest
import yammh3

from hypothesis import given, strategies as st
from yammh3 import get_include, hash128, hash64, hash32

def setup_class():
pass

def teardown_class():
pass
def partial(func, **default_kwargs):
@functools.wraps(func)
def wrapper(*args, **kwargs):
kwargs = dict(default_kwargs, **kwargs)
return func(*args, **kwargs)
wrapper.default_kwargs = default_kwargs
return wrapper


st_custom_seed = functools.partial(st.integers, 1, 2**32-1)

booleans = [False, True]

hash_funcs_defaults = [
hash32, hash64, hash128,
]

hash_funcs_signed = [
partial(hash32, signed=True),
] + [
partial(hash64, signed=True, low=low, x64=x64)
for low in booleans for x64 in booleans
] + [
partial(hash128, signed=True, x64=True),
partial(hash128, signed=True, x64=False),
]

hash_funcs_unsigned = [
partial(hash32, signed=False),
] + [
partial(hash64, signed=False, low=low, x64=x64)
for low in booleans for x64 in booleans
] + [
partial(hash128, signed=False, x64=True),
partial(hash128, signed=False, x64=False),
]


hash_funcs_all = hash_funcs_signed + hash_funcs_unsigned


def is_hash128_out(out):
return isinstance(out, tuple) and len(out) == 2


def assert_uint32(n):
assert 0 <= n < 2**32


def assert_int32(n):
assert -2**31 <= n < 2**31


def assert_uint64(n):
assert 0 <= n < 2**64


def assert_int64(n):
assert -2**63 <= n < 2**63


def assert_uint128(n):
assert is_hash128_out(n)
a, b = n
assert_uint64(a)
assert_uint64(b)


def assert_int128(n):
assert is_hash128_out(n)
a, b = n
assert_int64(a)
assert_int64(b)


def test_get_include():
path = get_include()
headers = glob.glob(os.path.join(path, '*.pxd'))
assert len(headers) > 0


@pytest.mark.parametrize('hash_func', hash_funcs_defaults)
@given(value=st.text(), seed=st_custom_seed())
def test_hash_default_signed(hash_func, value, seed):
out = hash_func(value, seed=seed)
out_signed = hash_func(value, signed=True, seed=seed)
assert out == out_signed


@pytest.mark.parametrize('hash_func', hash_funcs_all)
@given(value=st.text(), seed=st_custom_seed())
def test_hash_bytes(hash_func, value, seed):
out_default = hash_func(value.encode('utf8'))
out = hash_func(value, seed=seed)
assert out != out_default


@pytest.mark.parametrize('hash_func', hash_funcs_all)
@given(value=st.text(), seed=st_custom_seed())
def test_hash_custom_seed(hash_func, value, seed):
out_default = hash_func(value)
out = hash_func(value, seed=seed)
assert out != out_default


@pytest.mark.parametrize('hash_func', hash_funcs_unsigned)
@given(value=st.text(), seed=st_custom_seed())
def test_hash_unsigned(hash_func, value, seed):
out = hash_func(value, seed=seed)
if is_hash128_out(out):
assert out[0] >= 0 and out[1] >= 0
else:
assert out >= 0


@pytest.mark.parametrize('hash_func', hash_funcs_signed)
def test_hash_signed(hash_func):
# As we test random values, we stop once we find one negative.
@given(value=st.text(min_size=1), seed=st_custom_seed())
def find_negative(value, seed):
out = hash_func(value, seed=seed)
if is_hash128_out(out):
out = min(*out)
if out < 0:
raise FoundNegative

try:
find_negative()
except FoundNegative:
pass
else:
assert False, "Unable to find negative hash"


@pytest.mark.parametrize('hash_assert', [
(hash32, [assert_uint32, assert_int32]),
(hash64, [assert_uint64, assert_int64]),
(hash128, [assert_uint128, assert_int128]),
])
@given(value=st.text(), seed=st_custom_seed())
def test_hash_int_ranges(hash_assert, value, seed):
hash_func, (assert_u, assert_s) = hash_assert
assert_s(hash_func(value, seed=seed)) # default signed
assert_u(hash_func(value, seed=seed, signed=False))


@pytest.mark.parametrize('x64', booleans)
@given(value=st.text(), seed=st_custom_seed())
def test_hash64_is_hash128(x64, value, seed):
high = hash64(value, seed=seed, x64=x64) # default low=False
low = hash64(value, seed=seed, low=True, x64=x64)
out = hash128(value, seed=seed, x64=x64)
assert (high, low) == out


def test_something():
class FoundNegative(Exception):
pass
9 changes: 7 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@
envlist = py27, py35

[testenv]
deps = pytest
commands = {posargs:py.test}
deps =
cython
hypothesis
pytest
commands =
python setup_tests.py build_ext --inplace
{posargs:py.test}

; If you want to make tox run the tests with the same versions, create a
; requirements.txt with the pinned versions and uncomment the following lines:
Expand Down

0 comments on commit 23423f5

Please sign in to comment.