Skip to content
97 changes: 97 additions & 0 deletions exercises/rational-numbers/.meta/template.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
{%- import "generator_macros.j2" as macros with context -%}

{%- set operators = {
"add": "+",
"sub": "-",
"mul": "*",
"div": "/",
"exprational": "**",
"expreal": "**"
} -%}

{% macro test_case_arithmetic(case) -%}
{%- set r1 = "Rational({}, {})".format(case["input"]["r1"][0], case["input"]["r1"][1]) -%}
{%- set r2 = "Rational({}, {})".format(case["input"]["r2"][0], case["input"]["r2"][1]) -%}
{%- set expected = "Rational({}, {})".format(case["expected"][0], case["expected"][1]) -%}
{%- set operator = operators[case["property"]] -%}

def test_{{ case["description"] | to_snake }}(self):
self.assertEqual({{r1}} {{operator}} {{r2}}, {{expected}})
{%- endmacro %}

{% macro test_case_absolutevalue(case) -%}
{%- set r = "Rational({}, {})".format(case["input"]["r"][0], case["input"]["r"][1]) -%}
{%- set expected = "Rational({}, {})".format(case["expected"][0], case["expected"][1]) -%}
{%- set method = case["property"] -%}
def test_{{ case["description"] | to_snake }}(self):
self.assertEqual({{method}}({{r}}), {{expected}})
{%- endmacro %}

{% macro test_case_exponentiation(case) -%}
{%- set r = "Rational({}, {})".format(case["input"]["r"][0], case["input"]["r"][1]) -%}
{%- set n = case["input"]["n"] -%}
{%- set expected = "Rational({}, {})".format(case["expected"][0], case["expected"][1]) -%}
{%- set operator = operators[case["property"]] -%}

def test_{{ case["description"] | to_snake }}(self):
self.assertEqual({{r}} {{operator}} {{n}}, {{expected}})
{%- endmacro %}

{% macro test_case_exponentiation_real(case) -%}
{%- set x = case["input"]["x"] -%}
{%- set r = "Rational({}, {})".format(case["input"]["r"][0], case["input"]["r"][1]) -%}
{%- set expected = case["expected"] -%}
{%- set operator = operators[case["property"]] -%}

def test_{{ case["description"] | to_snake }}(self):
self.assertAlmostEqual({{x}} {{operator}} {{r}}, {{expected}}, places=8)
{%- endmacro %}

{% macro test_case_reduction(case) -%}
{%- set r = "Rational({}, {})".format(case["input"]["r"][0], case["input"]["r"][1]) -%}
{%- set expected = "Rational({}, {})".format(case["expected"][0], case["expected"][1]) -%}

def test_{{ case["description"] | to_snake }}(self):
self.assertEqual({{r}}, {{expected}})
{%- endmacro %}

{% macro render_arithmetic_cases(mathtypescases) -%}

{% for mathoperationcases in mathtypescases["cases"] %}
# {{ mathoperationcases["description"] }}
{% for case in mathoperationcases["cases"] %}
{{ test_case_arithmetic(case) }}
{% endfor %}
{% endfor %}

{%- endmacro %}

{% macro render_other_cases(mathtypescases) -%}

{% for case in mathtypescases["cases"] %}
{% if mathtypescases["description"] == 'Absolute value' %}
{{ test_case_absolutevalue(case) }}
{% elif mathtypescases["description"] == 'Exponentiation of a rational number' %}
{{ test_case_exponentiation(case) }}
{% elif mathtypescases["description"] == 'Exponentiation of a real number to a rational number' %}
{{ test_case_exponentiation_real(case) }}
{% elif mathtypescases["description"] == 'Reduction to lowest terms' %}
{{ test_case_reduction(case) }}
{% endif %}
{% endfor %}

{%- endmacro %}

from __future__ import division
{{ macros.header(imports=["Rational"]) }}

class {{ exercise | camel_case }}Test(unittest.TestCase):
{% for mathtypescases in cases %}
# Tests of type: {{ mathtypescases["description"] }}
{% if mathtypescases["description"] == 'Arithmetic' %}
{{ render_arithmetic_cases(mathtypescases) }}
{% else %}
{{ render_other_cases(mathtypescases) }}
{% endif %}
{% endfor %}
{{ macros.footer() }}
109 changes: 60 additions & 49 deletions exercises/rational-numbers/rational_numbers_test.py
Original file line number Diff line number Diff line change
@@ -1,93 +1,104 @@
from __future__ import division
Comment thread
GKotfis marked this conversation as resolved.

import unittest

from rational_numbers import Rational


# Tests adapted from `problem-specifications//canonical-data.json` @ v1.1.0


class RationalNumbersTest(unittest.TestCase):

# Test addition
def test_add_two_positive(self):
# Tests of type: Arithmetic

# Addition

def test_add_two_positive_rational_numbers(self):
self.assertEqual(Rational(1, 2) + Rational(2, 3), Rational(7, 6))

def test_add_positive_and_negative(self):
def test_add_a_positive_rational_number_and_a_negative_rational_number(self):
self.assertEqual(Rational(1, 2) + Rational(-2, 3), Rational(-1, 6))

def test_add_two_negative(self):
def test_add_two_negative_rational_numbers(self):
self.assertEqual(Rational(-1, 2) + Rational(-2, 3), Rational(-7, 6))

def test_add_opposite(self):
def test_add_a_rational_number_to_its_additive_inverse(self):
self.assertEqual(Rational(1, 2) + Rational(-1, 2), Rational(0, 1))

# Test subtraction
def test_subtract_two_positive(self):
# Subtraction

def test_subtract_two_positive_rational_numbers(self):
self.assertEqual(Rational(1, 2) - Rational(2, 3), Rational(-1, 6))

def test_subtract_positive_and_negative(self):
def test_subtract_a_positive_rational_number_and_a_negative_rational_number(self):
self.assertEqual(Rational(1, 2) - Rational(-2, 3), Rational(7, 6))

def test_subtract_two_negative(self):
def test_subtract_two_negative_rational_numbers(self):
self.assertEqual(Rational(-1, 2) - Rational(-2, 3), Rational(1, 6))

def test_subtract_from_self(self):
def test_subtract_a_rational_number_from_itself(self):
self.assertEqual(Rational(1, 2) - Rational(1, 2), Rational(0, 1))

# Test multiplication
def test_multiply_two_positive(self):
# Multiplication

def test_multiply_two_positive_rational_numbers(self):
self.assertEqual(Rational(1, 2) * Rational(2, 3), Rational(1, 3))

def test_multiply_negative_by_positive(self):
def test_multiply_a_negative_rational_number_by_a_positive_rational_number(self):
self.assertEqual(Rational(-1, 2) * Rational(2, 3), Rational(-1, 3))

def test_multiply_two_negative(self):
def test_multiply_two_negative_rational_numbers(self):
self.assertEqual(Rational(-1, 2) * Rational(-2, 3), Rational(1, 3))

def test_multiply_reciprocal(self):
def test_multiply_a_rational_number_by_its_reciprocal(self):
self.assertEqual(Rational(1, 2) * Rational(2, 1), Rational(1, 1))

def test_multiply_by_one(self):
def test_multiply_a_rational_number_by_1(self):
self.assertEqual(Rational(1, 2) * Rational(1, 1), Rational(1, 2))

def test_multiply_by_zero(self):
def test_multiply_a_rational_number_by_0(self):
self.assertEqual(Rational(1, 2) * Rational(0, 1), Rational(0, 1))

# Test division
def test_divide_two_positive(self):
# Division

def test_divide_two_positive_rational_numbers(self):
self.assertEqual(Rational(1, 2) / Rational(2, 3), Rational(3, 4))

def test_divide_positive_by_negative(self):
def test_divide_a_positive_rational_number_by_a_negative_rational_number(self):
self.assertEqual(Rational(1, 2) / Rational(-2, 3), Rational(-3, 4))

def test_divide_two_negative(self):
def test_divide_two_negative_rational_numbers(self):
self.assertEqual(Rational(-1, 2) / Rational(-2, 3), Rational(3, 4))

def test_divide_by_one(self):
def test_divide_a_rational_number_by_1(self):
self.assertEqual(Rational(1, 2) / Rational(1, 1), Rational(1, 2))

# Test absolute value
def test_absolute_value_of_positive(self):
# Tests of type: Absolute value

def test_absolute_value_of_a_positive_rational_number(self):
self.assertEqual(abs(Rational(1, 2)), Rational(1, 2))

def test_absolute_value_of_positive_negative_numerator_denominator(self):
def test_absolute_value_of_a_positive_rational_number_with_negative_numerator_and_denominator(
self
):
self.assertEqual(abs(Rational(-1, -2)), Rational(1, 2))

def test_absolute_value_of_negative(self):
def test_absolute_value_of_a_negative_rational_number(self):
self.assertEqual(abs(Rational(-1, 2)), Rational(1, 2))

def test_absolute_value_of_negative_with_negative_denominator(self):
def test_absolute_value_of_a_negative_rational_number_with_negative_denominator(
self
):
self.assertEqual(abs(Rational(1, -2)), Rational(1, 2))

def test_absolute_value_of_zero(self):
self.assertEqual(abs(Rational(0, 1)), Rational(0, 1))

# Test exponentiation of a rational number
def test_raise_a_positive_rational_to_a_positive_integer_power(self):
# Tests of type: Exponentiation of a rational number

def test_raise_a_positive_rational_number_to_a_positive_integer_power(self):
self.assertEqual(Rational(1, 2) ** 3, Rational(1, 8))

def test_raise_a_negative_rational_to_a_positive_integer_power(self):
def test_raise_a_negative_rational_number_to_a_positive_integer_power(self):
self.assertEqual(Rational(-1, 2) ** 3, Rational(-1, 8))

def test_raise_zero_to_an_integer_power(self):
Expand All @@ -96,43 +107,43 @@ def test_raise_zero_to_an_integer_power(self):
def test_raise_one_to_an_integer_power(self):
self.assertEqual(Rational(1, 1) ** 4, Rational(1, 1))

def test_raise_a_positive_rational_to_the_power_of_zero(self):
def test_raise_a_positive_rational_number_to_the_power_of_zero(self):
self.assertEqual(Rational(1, 2) ** 0, Rational(1, 1))

def test_raise_a_negative_rational_to_the_power_of_zero(self):
def test_raise_a_negative_rational_number_to_the_power_of_zero(self):
self.assertEqual(Rational(-1, 2) ** 0, Rational(1, 1))

# Test exponentiation of a real number to a rational number
def test_raise_a_real_number_to_a_positive_rational(self):
# Tests of type: Exponentiation of a real number to a rational number

def test_raise_a_real_number_to_a_positive_rational_number(self):
self.assertAlmostEqual(8 ** Rational(4, 3), 16.0, places=8)

def test_raise_a_real_number_to_a_negative_rational(self):
self.assertAlmostEqual(
9 ** Rational(-1, 2), 0.3333333333333333, places=8
)
def test_raise_a_real_number_to_a_negative_rational_number(self):
self.assertAlmostEqual(9 ** Rational(-1, 2), 0.3333333333333333, places=8)

def test_raise_a_real_number_to_a_zero_rational(self):
def test_raise_a_real_number_to_a_zero_rational_number(self):
self.assertAlmostEqual(2 ** Rational(0, 1), 1.0, places=8)

# Test reduction to lowest terms
def test_reduce_positive(self):
# Tests of type: Reduction to lowest terms

def test_reduce_a_positive_rational_number_to_lowest_terms(self):
self.assertEqual(Rational(2, 4), Rational(1, 2))

def test_reduce_negative(self):
def test_reduce_a_negative_rational_number_to_lowest_terms(self):
self.assertEqual(Rational(-4, 6), Rational(-2, 3))

def test_reduce_rational_with_negative_denominator(self):
def test_reduce_a_rational_number_with_a_negative_denominator_to_lowest_terms(self):
self.assertEqual(Rational(3, -9), Rational(-1, 3))

def test_reduce_zero(self):
def test_reduce_zero_to_lowest_terms(self):
self.assertEqual(Rational(0, 6), Rational(0, 1))

def test_reduce_integer(self):
def test_reduce_an_integer_to_lowest_terms(self):
self.assertEqual(Rational(-14, 7), Rational(-2, 1))

def test_reduce_one(self):
def test_reduce_one_to_lowest_terms(self):
self.assertEqual(Rational(13, 13), Rational(1, 1))


if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()