Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Further improvement of parameter operator test implementation #2631

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 43 additions & 46 deletions testsuite/pytests/test_parameter_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,24 @@
import operator as ops


def const_param(val):
def _const_param(val):
return nest.CreateParameter('constant', {'value': val})


def to_numeric(item):
return item.GetValue() if hasattr(item, 'GetValue') else item


@pytest.mark.parametrize('op, a, b', [
[ops.pow, const_param(31), const_param(5)],
[ops.pow, 31, const_param(5)],
[ops.mod, const_param(31), const_param(5)],
[ops.mod, const_param(31), 5],
[ops.pow, 31, const_param(5)]
[ops.mod, _const_param(31), _const_param(5)],
[ops.mod, _const_param(31), 5],
[ops.mod, 31, _const_param(5)]
])
def test_unsupported_operators(op, a, b):
"""
Test that unsupported operator-operand combinations raise a TypeError.

A side-purpose of this test is to document which operators are not fully supported.
A side-purpose of this test is to document unsupported operators.
"""

with pytest.raises(TypeError):
Expand All @@ -67,11 +69,11 @@ def test_unary_operators(op):
"""
Perform tests for unary operators.

Parametrization is over operators
Parametrization is over operators.
"""

val_a = 31
a = nest.CreateParameter('constant', {'value': val_a})
a = _const_param(val_a)

assert op(a).GetValue() == op(val_a)

Expand All @@ -83,9 +85,9 @@ def test_unary_operators(op):
ops.truediv
])
@pytest.mark.parametrize('a, b', [
[const_param(31), const_param(5)],
[31, const_param(5)],
[const_param(31), 5]
[_const_param(31), _const_param(5)],
[31, _const_param(5)],
[_const_param(31), 5]
])
def test_binary_operators(op, a, b):
"""
Expand All @@ -94,35 +96,37 @@ def test_binary_operators(op, a, b):
Outer parametrization is over operators, the inner over param-param, param-number and number-param combinations.
"""

# Extract underlying numerical value if we are passed a parameter object.
try:
val_a = a.GetValue()
except AttributeError:
val_a = a
try:
val_b = b.GetValue()
except AttributeError:
val_b = b
val_a = to_numeric(a)
val_b = to_numeric(b)
jougs marked this conversation as resolved.
Show resolved Hide resolved

assert op(a, b).GetValue() == op(val_a, val_b)


def _unsupported_binary_op(op, a, b):
"""
Represent test cases where at op is not supported for at least one of a or b.
heplesser marked this conversation as resolved.
Show resolved Hide resolved

The syntax for representing individual test cases with expected failure is much more
verbose than a simple `[op, a, b]`. This helper function returns the correct representation,
ensuring that unexpected passing will be marked as error. For consistency with general
Python behavior, we require that a `TypeError` is raised.
"""

return pytest.param(op, a, b, marks=pytest.mark.xfail(raises=TypeError, strict=True))


@pytest.mark.parametrize('op, a, b', [
[ops.pow, const_param(31), 5]])
[ops.pow, _const_param(31), 5],
_unsupported_binary_op(ops.pow, _const_param(31), _const_param(5)),
_unsupported_binary_op(ops.pow, 31, _const_param(5))
])
def test_incomplete_binary_operators(op, a, b):
"""
Perform tests for binary operators that do not support Parameter as any operand.
Perform tests for binary operators that do not support parameters as all operands.
"""

# Extract underlying numerical value if we are passed a parameter object.
try:
val_a = a.GetValue()
except AttributeError:
val_a = a
try:
val_b = b.GetValue()
except AttributeError:
val_b = b
val_a = to_numeric(a)
val_b = to_numeric(b)

assert op(a, b).GetValue() == op(val_a, val_b)

Expand All @@ -136,11 +140,11 @@ def test_incomplete_binary_operators(op, a, b):
ops.ge
])
@pytest.mark.parametrize('a, b', [
[const_param(31), const_param(31)],
[const_param(31), 31],
[31, const_param(31)],
[const_param(31), const_param(5)],
[const_param(5), const_param(31)],
[_const_param(31), _const_param(31)],
[_const_param(31), 31],
[31, _const_param(31)],
[_const_param(31), _const_param(5)],
[_const_param(5), _const_param(31)],
])
def test_comparison_operators(op, a, b):
"""
Expand All @@ -149,14 +153,7 @@ def test_comparison_operators(op, a, b):
Outer parametrization is over operators, the inner over param-param, param-number and number-param combinations.
"""

# Extract underlying numerical value if we are passed a parameter object.
try:
val_a = a.GetValue()
except AttributeError:
val_a = a
try:
val_b = b.GetValue()
except AttributeError:
val_b = b
val_a = to_numeric(a)
val_b = to_numeric(b)

assert op(a, b).GetValue() == op(val_a, val_b)
159 changes: 159 additions & 0 deletions testsuite/pytests/test_parameter_operators.py.bak
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# -*- coding: utf-8 -*-
#
# test_parameter_operators.py
#
# This file is part of NEST.
#
# Copyright (C) 2004 The NEST Initiative
#
# NEST is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# NEST 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
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with NEST. If not, see <http://www.gnu.org/licenses/>.

"""
Test that Parameters support arithmetic operations correctly.

This set of tests confirms that arithmetic operations on NEST Parameter objects yield
correct results by comparing with operations on the undelying numeric values.
It also confirms that operations on Parameter objects and plain numbers work.

.. note::

These tests only confirm that operators on parameters work in principle. Therefore,
we can use constant parameters for simplicity.
"""

import nest
import pytest
import operator as ops


def _const_param(val):
return nest.CreateParameter('constant', {'value': val})


def to_numeric(item):
return item.GetValue() if hasattr(item, 'GetValue') else item


@pytest.mark.parametrize('op, a, b', [
[ops.mod, _const_param(31), _const_param(5)],
[ops.mod, _const_param(31), 5],
[ops.mod, 31, _const_param(5)]
])
def test_unsupported_operators(op, a, b):
"""
Test that unsupported operator-operand combinations raise a TypeError.

A side-purpose of this test is to document unsupported operators.
"""

with pytest.raises(TypeError):
op(a, b)


@pytest.mark.parametrize('op', [
ops.neg,
ops.pos
])
def test_unary_operators(op):
"""
Perform tests for unary operators.

Parametrization is over operators.
"""

val_a = 31
a = _const_param(val_a)

assert op(a).GetValue() == op(val_a)


@pytest.mark.parametrize('op', [
ops.add,
ops.sub,
ops.mul,
ops.truediv
])
@pytest.mark.parametrize('a, b', [
[_const_param(31), _const_param(5)],
[31, _const_param(5)],
[_const_param(31), 5]
])
def test_binary_operators(op, a, b):
"""
Perform tests for binary operators.

Outer parametrization is over operators, the inner over param-param, param-number and number-param combinations.
"""

val_a = to_numeric(a)
val_b = to_numeric(b)

assert op(a, b).GetValue() == op(val_a, val_b)


def _unsupported_binary_op(op, a, b):
"""
Represent test cases where at op is not supported for at least one of a or b.

The syntax for representing individual test cases with expected failure is much more
verbose than a simple `[op, a, b]`. This helper function returns the correct representation,
ensuring that unexpected passing will be marked as error. For consistency with general
Python behavior, we require that a `TypeError` is raised.
"""

return pytest.param(op, a, b, marks=pytest.mark.xfail(raises=TypeError, strict=True))


@pytest.mark.parametrize('op, a, b', [
[ops.pow, _const_param(31), 5],
_unsupported_binary_op(ops.pow, _const_param(31), _const_param(5)),
_unsupported_binary_op(ops.pow, 31, _const_param(5))
])
def test_incomplete_binary_operators(op, a, b):
"""
Perform tests for binary operators that do not support parameters as all operands.
"""

val_a = to_numeric(a)
val_b = to_numeric(b)

assert op(a, b).GetValue() == op(val_a, val_b)


@pytest.mark.parametrize('op', [
ops.eq,
ops.ne,
ops.lt,
ops.le,
ops.gt,
ops.ge
])
@pytest.mark.parametrize('a, b', [
[_const_param(31), _const_param(31)],
[_const_param(31), 31],
[31, _const_param(31)],
[_const_param(31), _const_param(5)],
[_const_param(5), _const_param(31)],
])
def test_comparison_operators(op, a, b):
"""
Perform tests for comparison operators.

Outer parametrization is over operators, the inner over param-param, param-number and number-param combinations.
"""

val_a = to_numeric(a)
val_b = to_numeric(b)

assert op(a, b).GetValue() == op(val_a, val_b)