2011 Oct 02
#!/usr/bin/env python
"""Unit test test harness for space objects.
# TODO bundle tests
Note: test doc strings are printed in verbose mode.
This file is part of lrm's Orbits software library.
Orbits 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 3 of the License, or
(at your option) any later version.
Orbits 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 Orbits. If not, see <http://www.gnu.org/licenses/>.
"""
import math
import unittest
import space
class TestSpace(unittest.TestCase):
def setUp(self):
"""Set up test parameters.
TOOD test each xyz path for int, float? and sign?
TODO access to unit vectors.
TODO: is it circular to "test" the constructors here?
"""
self.places = 7 # almost equal places
# various types to check math operators
self.most_exception_types = (
'foo', 0, 1, -2, 3.1415, -2.7, complex(1.2, -3.4))
self.divisor_exception_types = ('foo', complex(1.2, -3.4))
# one point
self.x1 = 1
self.y1 = 2
self.z1 = 3
self.space1 = space.space(self.x1, self.y1, self.z1)
self.space1_mag = math.sqrt(self.x1*self.x1 + self.y1*self.y1 + self.z1*self.z1)
self.normal1 = space.space(self.x1/self.space1_mag,
self.y1/self.space1_mag,
self.z1/self.space1_mag)
# hardcoded strings keep this from being too circular.
self.one_as_str = '1 2 3 '
self.one_as_repr = '(1, 2, 3)'
# another point
self.x2 = 0.123456789
self.y2 = -2.71828
self.z2 = 3.14159
self.space2 = space.space(self.x2, self.y2, self.z2)
# Note: space print precision (default) is less than in Body.
self.two_as_str = '0.123457 -2.71828 3.14159 '
self.two_as_repr = '(0.123457, -2.71828, 3.14159)'
# sum
self.sum_space1_space2 = space.space(self.x1 + self.x2,
self.y1 + self.y2,
self.z1 + self.z2)
# difference
self.diff_space1_space2 = space.space(self.x1 - self.x2,
self.y1 - self.y2,
self.z1 - self.z2)
# dot product
self.dot_prod_space1_space2 = \
self.x1 * self.x2 + \
self.y1 * self.y2 + \
self.z1 * self.z2
self.quotient_space1_over_2 = space.space(self.x1 / 2.0,
self.y1 / 2.0,
self.z1 / 2.0)
def assertSpaceAreEqual(self, lhs_space, rhs_space):
"""Helper function."""
self.assertAlmostEqual(lhs_space.x, rhs_space.x, places=self.places)
self.assertAlmostEqual(lhs_space.y, rhs_space.y, places=self.places)
self.assertAlmostEqual(lhs_space.z, rhs_space.z, places=self.places)
def test_constructors(self):
"""Test space constructors"""
a = space.space()
self.assertEqual(a.x, 0)
self.assertEqual(a.y, 0)
self.assertEqual(a.z, 0)
self.assertSpaceAreEqual(a, space.Uo)
a = space.space(self.x1)
self.assertEqual(a.x, self.x1)
self.assertEqual(a.y, 0)
self.assertEqual(a.z, 0)
a = space.space(self.x1, self.y1)
self.assertEqual(a.x, self.x1)
self.assertEqual(a.y, self.y1)
self.assertEqual(a.z, 0)
a = space.space(self.x1, self.y1, self.z1)
self.assertSpaceAreEqual(self.space1, a)
a = space.space(z=self.z2, x=self.x2, y=self.y2)
self.assertSpaceAreEqual(self.space2, a)
def test_assignments(self):
"""Test space assignment operators"""
a = space.space()
a.x = self.x1
a.y = self.y1
a.z = self.z1
self.assertSpaceAreEqual(self.space1, a)
# TODO assign to space
def test_exceptions(self):
"""Test space exceptions"""
a_space = space.space()
self.assertRaises(TypeError, a_space.x, 'foo')
self.assertRaises(TypeError, a_space.y, 'foo')
self.assertRaises(TypeError, a_space.z, 'foo')
# assert exceptions on operators of different types.
if False:
# FN
self.assertRaises(TypeError, lambda a, b: a + b,
self.space1, self.space2)
for type_ in self.most_exception_types:
self.assertRaises(TypeError, lambda a, b: a + b, a_space, type_)
self.assertRaises(TypeError, lambda a, b: b + a, a_space, type_)
# TODO +=
for type_ in self.most_exception_types:
self.assertRaises(TypeError, lambda a, b: a - b, a_space, type_)
self.assertRaises(TypeError, lambda a, b: b - a, a_space, type_)
# TODO -=
for type_ in self.most_exception_types:
self.assertRaises(TypeError, lambda a, b: a * b, a_space, type_)
self.assertRaises(TypeError, lambda a, b: b * a, a_space, type_)
# TODO *=
for type_ in self.divisor_exception_types:
self.assertRaises(TypeError, lambda a, b: a / b, a_space, type_)
self.assertRaises(TypeError, lambda a, b: b / a, a_space, type_)
# TODO /=
# divide by 0
self.assertRaises(space.space_error, lambda a, b: a / b, a_space, 0)
# TODO other exceptions
def test_prints(self):
"""Test space print and repr"""
a = space.space(self.x2, self.y2, self.z2)
self.assertEqual(self.two_as_str, str(a))
self.assertEqual(self.two_as_repr, repr(a))
# TODO ints?
def test_add(self):
"""Test space add"""
# operator+
a = self.space1 + self.space2
self.assertSpaceAreEqual(a, self.sum_space1_space2)
# operator+=
a = self.space1
a += self.space2
self.assertSpaceAreEqual(a, self.sum_space1_space2)
# was causing a Segmentation fault when += implementation
# was not making a copy of m_space (refence count problem?)
a # reference test
def test_subtract(self):
"""Test space subtract"""
# operator-
a = self.space1 - self.space2
self.assertSpaceAreEqual(a, self.diff_space1_space2)
# operator -=
a = self.space1
a -= self.space2
self.assertSpaceAreEqual(a, self.diff_space1_space2)
a # reference test
def test_multiply(self):
"""Test space multiply (dot product)"""
# operator*
a = self.space1 * self.space2
self.assertEqual(a, self.dot_prod_space1_space2)
# operator*=
a = self.space1
a *= self.space2
self.assertEqual(a, self.dot_prod_space1_space2)
a # reference test
def test_divide(self):
"""Test space divide (scale)"""
# operator/
a = self.space1 / 2.0
self.assertSpaceAreEqual(a, self.quotient_space1_over_2)
# operator*=
a = self.space1
a /= 2.0
self.assertSpaceAreEqual(a, self.quotient_space1_over_2)
a # reference test
def test_cross_product(self):
"""Test space cross product"""
# simple axis rotation.
a = space.cross(space.Ux, space.Uy)
self.assertSpaceAreEqual(a, space.Uz)
a = space.cross(space.Uy, space.Uz)
self.assertSpaceAreEqual(a, space.Ux)
a = space.cross(space.Uz, space.Ux)
self.assertSpaceAreEqual(a, space.Uy)
# TODO reverse cross when multiply methods are available.
# more complex
a = space.space(1, 1, 1)
b = space.space(0, 0, 0.5)
c = space.cross(a, b)
self.assertSpaceAreEqual(space.space(0.5, -0.5, 0), c)
def test_normalized(self):
"""Test space normalized"""
a = space.normalized(self.space1)
self.assertSpaceAreEqual(a, self.normal1)
def test_magnitude(self):
"""Test space magnitude"""
a = space.magnitude(self.space1)
self.assertAlmostEqual(a, self.space1_mag, self.places)
if __name__ == '__main__':
unittest.main()