def test_the_color_when_a_ray_misses():
    # Given
    w = default_world()
    r = Ray(Point(0, 0, -5), Vector(0, 1, 0))
    # When
    c = w.color_at(r)
    # Then
    assert c == Color(0, 0, 0)
def test_the_color_when_a_ray_hits():
    # Given
    w = default_world()
    r = Ray(Point(0, 0, -5), Vector(0, 0, 1))
    # When
    c = w.color_at(r)
    # Then
    assert c == Color(0.38066, 0.47583, 0.2855)
def test_the_refracted_color_with_an_opaque_surface():
    # Given
    w = default_world()
    shape = w.objects[0]
    r = Ray(Point(0, 0, -5), Vector(0, 0, 1))
    xs = Intersections(Intersection(4, shape), Intersection(6, shape))
    # When
    comps = xs[0].prepare_computations(r, xs)
    c = w.refracted_color(comps, 5)
    # Then
    assert c == Color(0, 0, 0)
def test_shading_an_intersection():
    # Given
    w = default_world()
    r = Ray(Point(0, 0, -5), Vector(0, 0, 1))
    shape = w.objects[0]
    i = Intersection(4, shape)
    # When
    comps = i.prepare_computations(r)
    c = w.shade_hit(comps)
    # Then
    assert c == Color(0.38066, 0.47583, 0.2855)
def test_rendering_a_world_with_a_camera():
    # Given
    w = default_world()
    c = Camera(11, 11, pi / 2)
    f = Point(0, 0, -5)
    to = Point(0, 0, 0)
    up = Vector(0, 1, 0)
    c.transform = view_transform(f, to, up)
    # When
    image = c.render(w)
    # Then
    assert image.pixel_at(5, 5) == Color(0.38066, 0.47583, 0.2855)
def test_shading_an_intersection_from_the_inside():
    # Given
    w = default_world()
    w.light = PointLight(Point(0, 0.25, 0), Color(1, 1, 1))
    r = Ray(Point(0, 0, 0), Vector(0, 0, 1))
    shape = w.objects[1]
    i = Intersection(0.5, shape)
    # When
    comps = i.prepare_computations(r)
    c = w.shade_hit(comps)
    # Then
    assert c == Color(0.90498, 0.90498, 0.90498)
def test_intersect_a_world_with_a_ray():
    # Given
    w = default_world()
    r = Ray(Point(0, 0, -5), Vector(0, 0, 1))
    # When
    xs = w.intersect_world(r)
    # Then
    assert len(xs) == 4
    assert xs[0].t == 4
    assert xs[1].t == 4.5
    assert xs[2].t == 5.5
    assert xs[3].t == 6
def test_the_reflected_color_for_a_nonreflective_material():
    # Given
    w = default_world()
    r = Ray(Point(0, 0, 0), Vector(0, 0, 1))
    shape = Sphere()
    shape.material.ambient = 1
    i = Intersection(1, shape)
    # When
    comps = i.prepare_computations(r)
    color = w.reflected_color(comps)
    # Then
    assert color == Color(0, 0, 0)  # black
def test_the_color_with_an_intersection_behind_the_ray():
    # Given
    w = default_world()
    outer = w.objects[0]
    outer.material.ambient = 1
    inner = w.objects[1]
    inner.material.ambient = 1
    r = Ray(Point(0, 0, 0.75), Vector(0, 0, -1))
    # When
    c = w.color_at(r)
    # Then
    assert c == inner.material.color
def test_the_refracted_color_at_the_maximum_recursive_depth():
    # Given
    w = default_world()
    shape = w.objects[0]
    shape.material.transparency = 1.0
    shape.material.refractive_index = 1.5
    r = Ray(Point(0, 0, -5), Vector(0, 0, 1))
    xs = Intersections(Intersection(4, shape), Intersection(6, shape))
    # When
    comps = xs[0].prepare_computations(r, xs)
    c = w.refracted_color(comps, 0)
    # Then
    assert c == Color(0, 0, 0)
def test_the_reflected_color_at_the_maximum_recursive_depth():
    # Given
    w = default_world()
    shape = Plane()
    shape.material.reflective = 0.5
    shape.transform = translation(0, -1, 0)
    w.objects.append(shape)
    r = Ray(Point(0, 0, -3), Vector(0, -sqrt(2) / 2, sqrt(2) / 2))
    i = Intersection(sqrt(2), shape)
    # When
    comps = i.prepare_computations(r)
    color = w.reflected_color(comps, 0)
    # Then
    assert color == Color(0, 0, 0)
def test__shade_hit__with_a_reflective_material():
    # Given
    w = default_world()
    shape = Plane()
    shape.material.reflective = 0.5
    shape.transform = translation(0, -1, 0)
    w.objects.append(shape)
    r = Ray(Point(0, 0, -3), Vector(0, -sqrt(2) / 2, sqrt(2) / 2))
    i = Intersection(sqrt(2), shape)
    # When
    comps = i.prepare_computations(r)
    color = w.shade_hit(comps)
    # Then
    assert color == Color(0.87675, 0.92434, 0.82918)
def test_default_world():
    # Given
    light = PointLight(Point(-10, 10, -10), Color(1, 1, 1))
    s1 = Sphere()
    s1.material.color = Color(0.8, 1.0, 0.6)
    s1.material.diffuse = 0.7
    s1.material.specular = 0.2
    s2 = Sphere()
    s2.transform = scaling(0.5, 0.5, 0.5)
    # When
    w = default_world()
    # Then
    assert w.light == light
    assert s1 in w.objects
    assert s2 in w.objects
def test_the_refracted_color_under_total_internal_reflection():
    # Given
    w = default_world()
    shape = w.objects[0]
    shape.material.transparency = 1.0
    shape.material.refractive_index = 1.5
    r = Ray(Point(0, 0, sqrt(2) / 2), Vector(0, 1, 0))
    xs = Intersections(Intersection(-sqrt(2) / 2, shape),
                       Intersection(sqrt(2) / 2, shape))
    # When

    # NOTE: this time you're inside the sphere, so you need
    # to look at the second intersection, xs[1], not xs[0]
    comps = xs[1].prepare_computations(r, xs)
    c = w.refracted_color(comps, 5)
    # Then
    assert c == Color(0, 0, 0)
def test_refracted_color_with_a_refracted_ray():
    # Then
    w = default_world()

    A = w.objects[0]
    A.material.ambient = 1.0
    A.material.pattern = MockPattern()

    B = w.objects[1]
    B.material.transparency = 1.0
    B.material.refractive_index = 1.5

    r = Ray(Point(0, 0, 0.1), Vector(0, 1, 0))
    xs = Intersections(Intersection(-0.9899, A), Intersection(-0.4899, B),
                       Intersection(0.4899, B), Intersection(0.9899, A))
    # When
    comps = xs[2].prepare_computations(r, xs)
    c = w.refracted_color(comps, 5)
    # Then
    assert c == Color(0, 0.99887, 0.04721)
def test__shade_hit__with_a_transparent_material():
    # Given
    w = default_world()

    floor = Plane()
    floor.transform = translation(0, -1, 0)
    floor.material.transparency = 0.5
    floor.material.refractive_index = 1.5
    w.objects.append(floor)

    ball = Sphere()
    ball.material.color = Color(1, 0, 0)
    ball.material.ambient = 0.5
    ball.transform = translation(0, -3.5, -0.5)
    w.objects.append(ball)

    r = Ray(Point(0, 0, -3), Vector(0, -sqrt(2) / 2, sqrt(2) / 2))
    xs = Intersections(Intersection(sqrt(2), floor))
    # When
    comps = xs[0].prepare_computations(r, xs)
    color = w.shade_hit(comps, 5)
    # Then
    assert color == Color(0.93642, 0.68642, 0.68642)
def test_there_is_no_shadow_when_nothing_is_collinear_with_point_and_light():
    # Given
    w = default_world()
    p = Point(0, 10, 0)
    # Then
    assert w.is_shadowed(p) is False
def test_there_is_no_shadow_when_an_object_is_behind_the_point():
    # Given
    w = default_world()
    p = Point(-2, 2, -2)
    # Then
    assert w.is_shadowed(p) is False
def test_the_shadow_when_an_object_is_between_the_point_and_the_light():
    # Given
    w = default_world()
    p = Point(10, -10, 10)
    # Then
    assert w.is_shadowed(p) is True