def run_test_init():
    """ Tests the   __init__   method of the Line class. """
    if not start_test('__init__'):
        return

    # -------------------------------------------------------------------------
    # Tests using one line:
    # -------------------------------------------------------------------------
    start = m1.Point(12, 88)
    end = m1.Point(40, 33)
    start_clone = start.clone()
    end_clone = end.clone()

    line = m1.Line(start, end)  # Causes __init__ to run

    # Test whether  start  is set correctly.
    expected = start_clone
    actual = line.start
    evaluate_test(expected, actual, 'Testing START:')

    # Test whether  end  is set correctly.
    expected = end_clone
    actual = line.end
    evaluate_test(expected, actual, 'Testing END:')

    # Testing whether __init__ CLONED its arguments:
    message = '\n  *** ERROR: FAILED to CLONE the {} argument. ***'
    if line.start is start:
        print_failure(message.format('START'))
    if line.end is end:
        print_failure(message.format('END'))

    # -------------------------------------------------------------------------
    # Tests using another line:
    # -------------------------------------------------------------------------
    start = m1.Point(-10, 111)
    end = m1.Point(222, -20)
    start_clone = start.clone()
    end_clone = end.clone()

    line = m1.Line(start, end)  # Causes __init__ to run

    # Test whether  start  is set correctly.
    expected = start_clone
    actual = line.start
    evaluate_test(expected, actual, 'Testing START:')

    # Test whether  end  is set correctly.
    expected = end_clone
    actual = line.end
    evaluate_test(expected, actual, 'Testing END:')

    # Testing whether __init__ CLONED its arguments:
    message = '\n  *** ERROR: FAILED to CLONE the {} argument. ***'
    if line.start is start:
        print_failure(message.format('START'))
    if line.end is end:
        print_failure(message.format('END'))

    end_test()
def run_test_get_number_of_clones():
    """ Tests the   get_number_of_clones   method of the Line class. """
    if not start_test('get_number_of_clones'):
        return

    line1 = m1.Line(m1.Point(500, 20), m1.Point(100, 8))
    line1.reverse()
    line2 = line1.clone()
    line1.reverse()
    line2.reverse()
    line2.x = m1.Point(0, 0)
    line3 = line1.clone()
    line4 = line3.clone()
    line5 = line1.clone()

    expected = 3
    actual = line1.get_number_of_clones()
    evaluate_test(expected, actual, 'Testing line1, cloned 3 times:')

    expected = 0
    actual = line2.get_number_of_clones()
    evaluate_test(expected, actual, 'Testing line2, never cloned:')

    expected = 1
    actual = line3.get_number_of_clones()
    evaluate_test(expected, actual, 'Testing line3, cloned once:')

    expected = 0
    actual = line4.get_number_of_clones()
    evaluate_test(expected, actual, 'Testing line4, never cloned:')

    expected = 0
    actual = line5.get_number_of_clones()
    evaluate_test(expected, actual, 'Testing line5, not yet cloned:')

    line3 = line5.clone()

    expected = 0
    actual = line3.get_number_of_clones()
    evaluate_test(expected, actual, 'Testing line3, now a new Line')

    expected = 1
    actual = line5.get_number_of_clones()
    evaluate_test(expected, actual, 'Testing line5, cloned once:')

    line5 = line1
    expected = 3
    actual = line5.get_number_of_clones()
    evaluate_test(expected, actual, 'Testing line5, now same as line1:')

    end_test()
def run_test_midpoint():
    """ Tests the   midpoint   method of the Line class. """
    if not start_test('midpoint'):
        return

    line = m1.Line(m1.Point(-10, 50),
                   m1.Point(30, 20))  # midpoint is (10, 35)

    expected = m1.Point(10.0, 35.0)
    actual = line.midpoint()
    evaluate_test(expected, actual, 'Testing the original line:')

    expected = m1.Point(10.0, 35.0)
    actual = line.midpoint()
    evaluate_test(expected, actual, 'Testing the original line again:')

    line.start = m1.Point(30.0, 10.0)
    expected = m1.Point(30.0, 15.0)
    actual = line.midpoint()
    evaluate_test(expected, actual, 'Testing a vertical line:')

    line.end = m1.Point(-30.0, 10.0)
    expected = m1.Point(0.0, 10.0)
    actual = line.midpoint()
    evaluate_test(expected, actual, 'Testing a horizontal line:')

    line.start = line.end
    expected = line.start.clone()
    actual = line.midpoint()
    evaluate_test(expected, actual, 'Testing a zero-length line:')

    end_test()
def run_test_length():
    """ Tests the   length   method of the Line class. """
    if not start_test('length'):
        return

    line1 = m1.Line(m1.Point(25, 2),
                    m1.Point(10, 7))  # Length is 15.8113883

    line2 = m1.Line(m1.Point(-30, 10),
                    m1.Point(-10, 20))  # Length is 22.3606798

    line3 = m1.Line(m1.Point(-100, 20),
                    m1.Point(300, 20))  # Horizontal line, length is 400

    line4 = m1.Line(m1.Point(30, 40),
                    m1.Point(30, 100))  # Vertical line, length is 60

    line5 = m1.Line(m1.Point(100, 200),
                    m1.Point(100, 200))  # Length is 0

    # These tests round all numbers to 6 decimal places before
    # doing the test for equality.  This is necessary since here we
    # are dealing with floating point numbers that may be computed
    # slightly differently (but with both ways correct).

    # ACTUALLY, I think that __eq__ in the Point class now takes
    # care of the floating-point roundoff.

    expected = round(15.8113883, 6)
    actual = round(line1.length(), 6)
    evaluate_test(expected, actual, 'Testing a negative-slope line:')

    expected = round(22.3606798, 6)
    actual = round(line2.length(), 6)
    evaluate_test(expected, actual, 'Testing a fractional-slope line:')

    expected = round(400.0, 6)
    actual = round(line3.length(), 6)
    evaluate_test(expected, actual, 'Testing a horizontal line')

    expected = round(60.0, 6)
    actual = round(line4.length(), 6)
    evaluate_test(expected, actual, 'Testing a vertical line:')

    expected = round(0.0, 6)
    actual = round(line5.length(), 6)
    evaluate_test(expected, actual, 'Testing a length-zero line:')

    end_test()
def run_test_reverse():
    """ Tests the   reverse   method of the Line class. """
    if not start_test('reverse'):
        return

    # -------------------------------------------------------------------------
    # Tests using one line:
    # -------------------------------------------------------------------------
    line = m1.Line(m1.Point(12, 88),
                   m1.Point(40, 33))

    original_start = line.start
    original_end = line.end
    line_clone = m1.Line(m1.Point(12, 88),
                         m1.Point(40, 33))

    # -------------------------------------------------------------------------
    # Reverse the first time:
    # -------------------------------------------------------------------------
    line.reverse()

    expected = original_end
    actual = line.start
    evaluate_test(expected, actual, 'Testing START after 1st reverse:')
    if (expected == actual) and (expected is not actual):
        print_failure()
        print_failure('      START is a CLONE of the original END')
        print_failure('      instead of the original END itself.')

    expected = original_start
    actual = line.end
    evaluate_test(expected, actual, 'Testing END after 1st reverse:')
    if (expected == actual) and (expected is not actual):
        print_failure()
        print_failure('      END is a CLONE of the original START')
        print_failure('      instead of the original START itself.')

    # -------------------------------------------------------------------------
    # After another reverse, line should be back to the original line.
    # -------------------------------------------------------------------------
    line.reverse()

    expected = line_clone
    actual = line
    evaluate_test(expected, actual, 'Testing after the 2nd reverse:')

    end_test()
def run_test_slope():
    """ Tests the   slope   method of the Line class. """
    if not start_test('slope'):
        return

    line1 = m1.Line(m1.Point(2, 25),
                    m1.Point(7, 10))  # Slope is -3

    line2 = m1.Line(m1.Point(-30, 10),
                    m1.Point(-10, 20))  # Slope is 0.5

    line3 = m1.Line(m1.Point(-100, 20),
                    m1.Point(300, 20))  # Slope is 0

    line4 = m1.Line(m1.Point(30, 40),
                    m1.Point(30, 100))  # Slope is math.inf

    expected = -3.0
    actual = line1.slope()
    evaluate_test(expected, actual, 'Testing a negative slope:')

    expected = 0.5
    actual = line2.slope()
    evaluate_test(expected, actual, 'Testing a fractional slope:')

    expected = 0.0
    actual = line3.slope()
    if actual == -0.0:
        expected = -0.0  # Both positive and negative zero are correct.
    evaluate_test(expected, actual, 'Testing a horizontal line')

    expected = math.inf
    actual = line4.slope()
    evaluate_test(expected, actual, 'Testing a vertical line:')

    end_test()
def run_test_reset():
    """ Tests the   reset   method of the Line class. """
    if not start_test('reset'):
        return

    p1 = m1.Point(55, 66)
    p2 = m1.Point(77, 88)
    p3 = m1.Point(0, 0)
    p4 = m1.Point(-100, -2)
    line1 = m1.Line(p1.clone(), p2.clone())
    line2 = m1.Line(p3.clone(), p4.clone())
    line3 = m1.Line(p1.clone(), p3.clone())

    line1.start = m1.Point(100, 300)
    line2.end = m1.Point(99, 4)
    line1.reverse()
    line1.reverse()
    line2.reverse()
    line3.reverse()

    # -------------------------------------------------------------------------
    # Testing line1 BEFORE the reset, then AFTER the reset.
    # -------------------------------------------------------------------------
    expected = False
    actual = (line1 == m1.Line(p1, p2))
    evaluate_test(expected, actual, 'Testing line1 BEFORE the reset:')

    line1.reset()

    expected = m1.Line(p1, p2)
    actual = line1
    evaluate_test(expected, actual, 'Testing line1 AFTER the reset:')

    # -------------------------------------------------------------------------
    # Testing line2 BEFORE the reset, then AFTER the reset.
    # -------------------------------------------------------------------------
    expected = False
    actual = (line2 == m1.Line(p3, p4))
    evaluate_test(expected, actual, 'Testing line2 BEFORE the reset:')

    line2.reset()

    expected = m1.Line(p3, p4)
    actual = line2
    evaluate_test(expected, actual, 'Testing line2 AFTER the reset:')

    # -------------------------------------------------------------------------
    # Testing line3 BEFORE the reset, then AFTER the reset.
    # -------------------------------------------------------------------------
    expected = False
    actual = (line3 == m1.Line(p1, p3))
    evaluate_test(expected, actual, 'Testing line3 BEFORE the reset:')

    line3.reset()

    expected = m1.Line(p1, p3)
    actual = line3
    evaluate_test(expected, actual, 'Testing line3 AFTER the reset:')

    # -------------------------------------------------------------------------
    # Testing MANY resets, then ONLY resets.
    # -------------------------------------------------------------------------
    for _ in range(99):
        line1.reverse()
        line1.reset()

    expected = m1.Line(p1, p2)
    actual = line1
    evaluate_test(expected, actual, 'Testing line1 after MANY resets')

    line3 = m1.Line(p1.clone(), p4.clone())
    for _ in range(1001):
        line3.reset()

    expected = m1.Line(p1, p4)
    actual = line3
    evaluate_test(expected, actual, 'Testing line3 after ONLY resets')

    # -------------------------------------------------------------------------
    # Testing whether the code CLONED when it stored the original Points
    # for retrieval by reset.
    # -------------------------------------------------------------------------
    line4 = m1.Line(m1.Point(66, 77),
                    m1.Point(88, 99))
    line4.start.x = 100
    line4.reset()

    expected = m1.Line(m1.Point(66, 77),
                       m1.Point(88, 99))
    actual = line4
    title = 'Testing whether the code CLONED when it stored the Points'
    evaluate_test(expected, actual, title)

    end_test()
def run_test_is_parallel():
    """ Tests the   is_parallel   method of the Line class. """
    if not start_test('is_parallel'):
        return

    # -------------------------------------------------------------------------
    # Tests using one pair of lines.  Each has slope -5.
    # -------------------------------------------------------------------------
    line1 = m1.Line(m1.Point(24, 10),
                    m1.Point(20, 30))
    line2 = m1.Line(m1.Point(60, -110),
                    m1.Point(68, -150))  # These both have slope -5

    expected = True
    actual = line1.is_parallel(line2)
    evaluate_test(expected, actual, 'Testing parallel lines:')

    expected = True
    actual = line2.is_parallel(line1)
    evaluate_test(expected, actual, 'Testing those lines again:')

    line1.reverse()
    expected = True
    actual = line1.is_parallel(line2)
    evaluate_test(expected, actual, 'Testing after reversing one line:')

    expected = True
    actual = line2.is_parallel(line1)
    evaluate_test(expected, actual, 'Testing that again:')

    # -------------------------------------------------------------------------
    # Modifying one of the lines, so that they are no longer parallel:
    # -------------------------------------------------------------------------
    line1.start.x = line1.start.x + 0.000001
    expected = False
    actual = line1.is_parallel(line2)
    evaluate_test(expected, actual, 'Testing lines no longer parallel:')

    expected = False
    actual = line2.is_parallel(line1)
    evaluate_test(expected, actual, 'Testing that again:')

    # -------------------------------------------------------------------------
    # Testing horizontal lines:
    # -------------------------------------------------------------------------
    line1 = m1.Line(m1.Point(88, 50),
                    m1.Point(99, 50))
    line2 = m1.Line(m1.Point(-100, 300),
                    m1.Point(-200, 300))  # These are both horizontal

    expected = True
    actual = line1.is_parallel(line2)
    evaluate_test(expected, actual, 'Testing parallel lines:')

    expected = True
    actual = line2.is_parallel(line1)
    evaluate_test(expected, actual, 'Testing those lines again:')

    line1.reverse()
    expected = True
    actual = line1.is_parallel(line2)
    evaluate_test(expected, actual, 'Testing after reversing one line:')

    expected = True
    actual = line2.is_parallel(line1)
    evaluate_test(expected, actual, 'Testing that again:')

    # Modifying one of the lines, so that they are no longer parallel:
    line2.end.y = line2.end.y + 0.000001
    expected = False
    actual = line1.is_parallel(line2)
    evaluate_test(expected, actual,
                  'Testing lines that are ALMOST parallel:')

    expected = False
    actual = line2.is_parallel(line1)
    evaluate_test(expected, actual, 'Testing that again:')

    # -------------------------------------------------------------------------
    # Testing vertical lines:
    # -------------------------------------------------------------------------
    line1 = m1.Line(m1.Point(77, 66),
                    m1.Point(77, -600))
    line2 = m1.Line(m1.Point(-110, 33),
                    m1.Point(-110, 300))  # These are both vertical

    expected = True
    actual = line1.is_parallel(line2)
    evaluate_test(expected, actual, 'Testing parallel lines:')

    expected = True
    actual = line2.is_parallel(line1)
    evaluate_test(expected, actual, 'Testing those lines again:')

    line1.reverse()
    expected = True
    actual = line1.is_parallel(line2)
    evaluate_test(expected, actual, 'Testing after reversing one line:')

    expected = True
    actual = line2.is_parallel(line1)
    evaluate_test(expected, actual, 'Testing that again:')

    # Modifying one of the lines, so that they are no longer parallel:
    line1.end.x = line1.end.x + 0.000001
    expected = False
    actual = line1.is_parallel(line2)
    evaluate_test(expected, actual,
                  'Testing lines that are ALMOST parallel:')

    expected = False
    actual = line2.is_parallel(line1)
    evaluate_test(expected, actual, 'Testing that again:')

    # -------------------------------------------------------------------------
    # Testing a situation where floating point arithmetic may say
    # that two slopes that are equal (in REAL arithmetic) are NOT equal.
    #
    # The code must ROUND in comparing the two slopes.
    # -------------------------------------------------------------------------
    line1 = m1.Line(m1.Point(24 * math.pi, 10),
                    m1.Point(20 * math.pi, 30))
    line2 = m1.Line(m1.Point(60 * math.pi, -110),
                    m1.Point(68 * math.pi, -150))

    expected = True
    actual = line1.is_parallel(line2)
    message = ('Testing two in-fact PARALLEL lines with slightly'
               + ' different computed slopes from round-off):')
    evaluate_test(expected, actual, message)

    end_test()
def run_test_line_minus():
    """ Tests the   line_minus   method of the Line class. """
    if not start_test('line_minus'):
        return

    line1 = m1.Line(m1.Point(500, 20), m1.Point(100, 8))
    line2 = m1.Line(m1.Point(100, 13), m1.Point(400, 8))

    expected = m1.Line(m1.Point(400, 7), m1.Point(-300, 0))
    actual = line1.line_minus(line2)
    evaluate_test(expected, actual, 'Testing line1 - line2:')

    expected = m1.Line(m1.Point(-400, -7), m1.Point(300, 0))
    actual = line2.line_minus(line1)
    evaluate_test(expected, actual, 'Testing line2 - line1:')

    expected = m1.Line(m1.Point(-900, -27), m1.Point(200, -8))
    actual = line2.line_minus(line1).line_minus(line1)
    evaluate_test(expected, actual, 'Testing line2 - line1 - line1:')

    expected = m1.Line(m1.Point(0, 0), m1.Point(0, 0))
    actual = line2.line_minus(line2)
    evaluate_test(expected, actual, 'Testing line2 - line2:')

    end_test()
def run_test_line_plus():
    """ Tests the   line_plus   method of the Line class. """
    if not start_test('line_plus'):
        return

    line1 = m1.Line(m1.Point(500, 20), m1.Point(100, 8))
    line2 = m1.Line(m1.Point(100, 13), m1.Point(400, 8))

    expected = m1.Line(m1.Point(600, 33), m1.Point(500, 16))
    actual = line1.line_plus(line2)
    evaluate_test(expected, actual, 'Testing line1 + line2:')

    expected = m1.Line(m1.Point(600, 33), m1.Point(500, 16))
    actual = line2.line_plus(line1)
    evaluate_test(expected, actual, 'Testing line2 + line1:')

    expected = m1.Line(m1.Point(1100, 53), m1.Point(600, 24))
    actual = line2.line_plus(line1).line_plus(line1)
    evaluate_test(expected, actual, 'Testing line2 + line1 + line1:')

    expected = m1.Line(m1.Point(200, 26), m1.Point(800, 16))
    actual = line2.line_plus(line2)
    evaluate_test(expected, actual, 'Testing line2 + line2:')

    end_test()
def run_test_clone():
    """ Tests the   clone   method of the Line class. """
    if not start_test('clone'):
        return

    # -------------------------------------------------------------------------
    # Tests using one line:
    # -------------------------------------------------------------------------
    start = m1.Point(12, 88)
    end = m1.Point(40, 33)
    start_clone = start.clone()
    end_clone = end.clone()

    line = m1.Line(start, end)
    clone = line.clone()

    # Test that the clone is a clone (copy), not just a 2nd reference.
    expected = True
    actual = (line == clone)
    evaluate_test(expected, actual, 'Testing that (line == clone):')

    expected = False
    actual = (line is clone)
    title = 'Testing that the line and clone are NOT the same object:'
    evaluate_test(expected, actual, title)

    expected = False
    actual = (line.start is clone.start)
    title = 'Testing that their START points are NOT the same object:'
    evaluate_test(expected, actual, title)

    expected = False
    actual = (line.end is clone.end)
    title = 'Testing that their END points are NOT the same object:'
    evaluate_test(expected, actual, title)

    # Change both line and clone.  Neither should affect the other.
    new_start = m1.Point(100, 200)
    new_end = m1.Point(300, 400)
    line.start = new_start
    clone.end = new_end

    # Test the clone:
    expected = start_clone
    actual = clone.start
    evaluate_test(expected, actual, 'Testing START for the clone:')

    expected = new_end
    actual = clone.end
    evaluate_test(expected, actual, 'Testing END for the clone:')

    # Test the line:
    expected = new_start
    actual = line.start
    evaluate_test(expected, actual, 'Testing START for the line:')

    expected = end_clone
    actual = line.end
    evaluate_test(expected, actual, 'Testing END for the line:')

    # -------------------------------------------------------------------------
    # Tests using another line:
    # -------------------------------------------------------------------------
    start = m1.Point(55, 66)
    end = m1.Point(77, 88)

    line = m1.Line(start, end)
    clone = line.clone()

    # Test that the clone is a clone (copy), not just a 2nd reference.
    expected = True
    actual = (line == clone)
    evaluate_test(expected, actual, 'Testing that (line == clone):')

    expected = False
    actual = (line is clone)
    title = 'Testing that the line and clone are NOT the same object:'
    evaluate_test(expected, actual, title)

    end_test()