Question: Complete the unit tests provided in the classesTestTwoDPointandTestQuadrilateral. Write unit test classesTestRectangleandTestSquare. In these classes, you must write unit test methods for Rectangle'scenter()andarea()methods, and Square'ssnap()method.
- Complete the unit tests provided in the classesTestTwoDPointandTestQuadrilateral.
- Write unit test classesTestRectangleandTestSquare. In these classes, you must write unit test methods for Rectangle'scenter()andarea()methods, and Square'ssnap()method.
test_quadrilateral.py
from unittest import TestCase
class TestQuadrilateral(TestCase):
def test_side_lengths(self):
self.fail()# TODO
def test_smallest_x(self):
self.fail()# TODO
test_twoDPoint.py
from unittest import TestCase
class TestTwoDPoint(TestCase):
def test_from_coordinates(self):
self.fail()# TODO
two_d_point.py
from typing import List
import math
class TwoDPoint:
def __init__(self, x, y) -> None:
self.__x = x
self.__y = y
@property
def x(self):
return self.__x
@property
def y(self):
return self.__y
def __eq__(self, other: object) -> bool:
if self.x == other.x and self.y == other.y:
return True
return False
def __ne__(self, other: object) -> bool:
return not self.__eq__(other)
def __str__(self) -> str:
return '(%g, %g)' % (self.__x, self.__y)
def __add__(self, other):
return TwoDPoint(self.x + other.x, self.y + other.y)
def __sub__(self, other):
return TwoDPoint(self.x - other.x, self.y - other.y)
@staticmethod
def from_coordinates(coordinates: List[float]):
if len(coordinates) % 2 != 0:
raise Exception("Odd number of floats given to build a list of 2-d points")
points = []
it = iter(coordinates)
for x in it:
points.append(TwoDPoint(x, next(it)))
return points
def distance(self, other) -> float:
"""
This method calculates the distance between two points.
"""
return math.sqrt((self.x-other.x)*(self.x-other.x) + (self.y-other.y)*(self.y-other.y))
quadrilateral.py
from two_d_point import TwoDPoint
class Quadrilateral:
def __init__(self, *floats):
points = TwoDPoint.from_coordinates(list(floats))
self.__vertices = tuple(points[0:4])
@property
def vertices(self):
return self.__vertices
def side_lengths(self):
"""Returns a tuple of four floats, each denoting the length of a side of this quadrilateral. The value must be
ordered clockwise, starting from the top left corner."""
# Finding the center of the quadrlateral.
center = self.vertices[0] + self.vertices[1] + self.vertices[2] + self.vertices[3]
center = TwoDPoint(center.x/4, center.y/4)
# Stores the points of the quadrilateral in clockwise order,
# starting from top-left.
point_in_order = [None, None, None, None]
# Adding the points in order.
for i in range(0, len(self.vertices)):
if self.vertices[i].x <= center.x and self.vertices[i].y >= center.y:
point_in_order[0] = self.vertices[i]
elif self.vertices[i].x >= center.x and self.vertices[i].y >= center.y:
point_in_order[1] = self.vertices[i]
elif self.vertices[i].x >= center.x and self.vertices[i].y <= center.y:
point_in_order[2] = self.vertices[i]
elif self.vertices[i].x <= center.x and self.vertices[i].y <= center.y:
point_in_order[3] = self.vertices[i]
# Calculating the distances between adjacent points.
distances = []
for i in range(0, len(point_in_order)):
distances.append(point_in_order[i].distance(point_in_order[(i+1)%4]))
# Return the distance as tuple.
return tuple(distances)
def smallest_x(self):
"""Returns the x-coordinate of the vertex with the smallest x-value of the four vertices of this
quadrilateral."""
# Stores the smallest x, initialized as the first point.
smallest_x = self.vertices[0].x
# Iterating over the points and calculating the smallest x
for point in self.vertices:
if point.x < smallest_x:
smallest_x = point.x
return smallest_x
rectangle.py
from quadrilateral import Quadrilateral
from two_d_point import TwoDPoint
class Rectangle(Quadrilateral):
def __init__(self, *floats):
super().__init__(*floats)
if not self.__is_member():
raise TypeError("A rectangle cannot be formed by the given coordinates.")
def __is_member(self):
"""Returns True if the given coordinates form a valid rectangle, and False otherwise."""
# Each x and y coordinate in a rectange should occur twice since the rectangle
# is alligned with the axes. We use this to determine if it's a rectangle.
# Stores the count of x coordinates.
x_coordinates = {}
# Stores the count of y coordinates.
y_coordinates = {}
# Counting the occurance of each x and y coordinate.
for point in self.vertices:
if point.x in x_coordinates:
x_coordinates[point.x] += 1
else:
x_coordinates[point.x] = 1
if point.y in y_coordinates:
y_coordinates[point.y] += 1
else:
y_coordinates[point.y] = 1
# Checking if each coordinate occurs two times.
for x in x_coordinates:
if x_coordinates[x] != 2:
return False
for y in y_coordinates:
if y_coordinates[y] != 2:
return False
return True
def center(self):
center = self.vertices[0] + self.vertices[1] + self.vertices[2] + self.vertices[3]
return TwoDPoint(center.x/4, center.y/4)
def area(self):
"""Returns the area of this rectangle. The implementation invokes the side_lengths() method from the superclass,
and computes the product of this rectangle's length and width."""
side_lengths = self.side_lengths()
return side_lengths[0]*side_lengths[1]
square.py
from two_d_point import TwoDPoint
from rectangle import Rectangle
from quadrilateral import Quadrilateral
class Square(Rectangle):
def __init__(self, *floats):
super().__init__(*floats)
if not self.__is_member():
raise TypeError("A square cannot be formed by the given coordinates.")
def __is_member(self):
# The adjacent sides of the square should be equal.
side_lengths = self.side_lengths()
if side_lengths[0] != side_lengths[1]:
return False
return True
def snap(self):
"""Snaps the sides of the square such that each corner (x,y) is modified to be a corner (x',y') where x' is the
integer value closest to x and y' is the integer value closest to y. This, of course, may change the shape to a
general quadrilateral, hence the return type. The only exception is when the square is positioned in a way where
this approximation will lead it to vanish into a single point. In that case, a call to snap() will not modify
this square in any way."""
# Stores the snapped points.
snapped_points = []
for point in self.vertices:
snapped_points.append(TwoDPoint(round(point.x), round(point.y)))
# Checking that all snapped points are not equal,
# in which case the square itself is returned.
if snapped_points[0] == snapped_points[1] and snapped_points[0] == snapped_points[2] and snapped_points[0] == snapped_points[3]:
return self
# Returning the quadrilateral with snapped points.
return Quadrilateral(snapped_points[0].x, snapped_points[0].y, snapped_points[1].x, snapped_points[1].y, snapped_points[2].x, snapped_points[2].y, snapped_points[3].x, snapped_points[3].y)
Step by Step Solution
There are 3 Steps involved in it
Get step-by-step solutions from verified subject matter experts
