import pyfmi.testcase
import unittest

points = 5

class ProblemTests(pyfmi.testcase.SpeakingTestCase):
	def equal(self, tested, expected):
		if isinstance(tested, (int, long)):
			tested = self.user.rational(tested)
		if isinstance(expected, (int, long)):
			expected = self.user.rational(expected)
		return expected.num() == tested.num() and expected.den() == tested.den()

	def test_construction(self):
		self.assertEqual(self.user.rational(3, 5).den(), 5)
		self.assertEqual(self.user.rational(2, -3).den(), 3)
		self.assertEqual(self.user.rational(7).den(), 1)
		self.assertEqual(self.user.rational(0).num(), 0)
		self.assertEqual(self.user.rational(0).den(), 1)
		self.assertRaises(ValueError, self.user.rational, 0, 0)
		self.assertEqual(self.user.rational(-4, -5).num(), 4)
		self.assertEqual(self.user.rational(-4, -5).den(), 5)

	def test_operations_simple(self):
		# Equality
		self.assertEqual(self.user.rational(-3, 4), self.user.rational(3, -4))
		self.assertEqual(self.user.rational(2, 7), self.user.rational(4, 14))
		self.assertTrue(self.user.rational(2, 7) == self.user.rational(2, 7))
		# Simple arithmetics and comparison
		self.equal(self.user.rational(3, 4), self.user.rational(1, 4) + self.user.rational(1, 2))
		self.equal(-self.user.rational(1, 17), self.user.rational(-1, 17))
		self.equal(~self.user.rational(1, 6), self.user.rational(6, 1))
		self.equal(self.user.rational(3, 4) - self.user.rational(6, 8), self.user.rational(0, 1))
		self.equal(self.user.rational(0, 1), self.user.rational(0))
		self.equal(self.user.rational(0, 117), self.user.rational(0))
		self.assertTrue(self.user.rational(5, -6) < self.user.rational(1, 3) + self.user.rational(1, 2))
		self.assertTrue(self.user.rational(-3) < self.user.rational(-2))
		self.assertFalse(self.user.rational(4, -5) > self.user.rational(-3, 5))
		# Negation and invertion
		self.equal(~self.user.rational(4, 6), self.user.rational(3, 2))
		self.equal(~self.user.rational(-7, 3), self.user.rational(-3, 7))
		self.equal(-self.user.rational(3, 2), self.user.rational(-3, 2))

	def test_operations(self):
		# Multiplication
		self.equal(self.user.rational(3, 4) * 2, self.user.rational(3, 2))
		self.equal(self.user.rational(3, 4) * self.user.rational(2), self.user.rational(3, 2))
		self.equal(self.user.rational(2) * self.user.rational(3, 4), self.user.rational(3, 2))
		self.equal(2 * self.user.rational(3, 4), self.user.rational(3, 2))
		self.equal(0 * self.user.rational(3, 4), self.user.rational(0))
		self.equal(self.user.rational(3, 5) * self.user.rational(4, 14), self.user.rational(6, 35))
		self.equal(self.user.rational(-4, 5) * -1, self.user.rational(4, 5))
		self.equal(self.user.rational(0) * 0, self.user.rational(0))
		self.equal(self.user.rational(2, 3) * self.user.rational(-3, 2), self.user.rational(-1))
		self.equal(self.user.rational(7, -3) * self.user.rational(-3), self.user.rational(7))
		# Division
		self.equal(self.user.rational(3, 4) / 2, self.user.rational(3, 8))
		self.equal(self.user.rational(-2, 3) / self.user.rational(-1), self.user.rational(2, 3))
		# Power
		self.equal(self.user.rational(3, 4) ** 3, self.user.rational(3 ** 3, 4 ** 3))
		self.equal(self.user.rational(3, 4) ** -1, self.user.rational(4, 3))
		self.equal(self.user.rational(-3, 4) ** -2, self.user.rational(16, 9))
		self.equal(self.user.rational(-3, 4) ** -3, self.user.rational(-64, 27))
		# I've had enough...		

	def test_methods(self):
		# Partition
		self.assertEqual(self.user.rational(7, 2).partition(), (3, self.user.rational(1, 2)))
		self.assertEqual((self.user.rational(9, 5) + 3).partition(), (4, self.user.rational(4, 5)))
		self.assertEqual(self.user.rational(1, 3).partition(), (0, self.user.rational(1, 3)))
		self.assertEqual(self.user.rational(0).partition(), (0, self.user.rational(0, 1)))
		# Lowest common denominator
		self.assertEqual(self.user.rational(1, 3).lcd(self.user.rational(1, 2)), 6)
		self.assertEqual(self.user.rational(1).lcd(self.user.rational(0)), 1)
		self.assertEqual(self.user.rational(3, 5).lcd(self.user.rational(4, 5)), 5)
		self.assertEqual(self.user.rational(3, 10).lcd(self.user.rational(4, 10)), 10)

	def test_conversions(self):
		self.assertEqual(int(self.user.rational(5, 6)), 0)
		self.assertEqual(int(self.user.rational(12, 12)), 1)
		self.assertEqual(int(self.user.rational(-1)), -1)
		self.assertEqual(int(self.user.rational(0)), 0)
		self.assertEqual(long(self.user.rational(-7, 2)), -3L)
		self.assertEqual(long(self.user.rational(0)), 0L)
		self.assertEqual(long(self.user.rational(999)), 999L)
		# Here we test also for the returned type
		tests = [
			(float(self.user.rational(1, -2)), -0.5),
			(float(self.user.rational(84, 2)), 42.0),
			(float(self.user.rational(0)), 0.0),
		]
		for yours, mine in tests:
			self.assertEqual(yours, mine)
			self.assertTrue(isinstance(yours, type(mine)))


if __name__ == '__main__':
	ProblemTests.user_filename = 'p5.py'
	unittest.main()
