#!/usr/bin/env python
import unittest

import pytest

try:
    import numpy
except ImportError:
    numpy = None

import libtcodpy


def test_console_behaviour(console):
    assert not console


@pytest.mark.skip("takes too long")
def test_credits_long(console):
    libtcodpy.console_credits()


def test_credits(console):
    libtcodpy.console_credits_render(0, 0, True)
    libtcodpy.console_credits_reset()


def assert_char(console, x, y, ch=None, fg=None, bg=None):
    if ch is not None:
        try:
            ch = ord(ch)
        except TypeError:
            pass
        assert libtcodpy.console_get_char(console, x, y) == ch
    if fg is not None:
        assert libtcodpy.console_get_char_foreground(console, x, y) == fg
    if bg is not None:
        assert libtcodpy.console_get_char_background(console, x, y) == bg


def test_console_defaults(console, fg, bg):
    libtcodpy.console_set_default_foreground(console, fg)
    libtcodpy.console_set_default_background(console, bg)
    libtcodpy.console_clear(console)
    assert_char(console, 0, 0, None, fg, bg)


def test_console_set_char_background(console, bg):
    libtcodpy.console_set_char_background(console, 0, 0, bg, libtcodpy.BKGND_SET)
    assert_char(console, 0, 0, bg=bg)


def test_console_set_char_foreground(console, fg):
    libtcodpy.console_set_char_foreground(console, 0, 0, fg)
    assert_char(console, 0, 0, fg=fg)


def test_console_set_char(console, ch):
    libtcodpy.console_set_char(console, 0, 0, ch)
    assert_char(console, 0, 0, ch=ch)


def test_console_put_char(console, ch):
    libtcodpy.console_put_char(console, 0, 0, ch, libtcodpy.BKGND_SET)
    assert_char(console, 0, 0, ch=ch)


def console_put_char_ex(console, ch, fg, bg):
    libtcodpy.console_put_char_ex(console, 0, 0, ch, fg, bg)
    assert_char(console, 0, 0, ch=ch, fg=fg, bg=bg)


def test_console_printing(console, fg, bg):
    libtcodpy.console_set_background_flag(console, libtcodpy.BKGND_SET)
    assert libtcodpy.console_get_background_flag(console) == libtcodpy.BKGND_SET

    libtcodpy.console_set_alignment(console, libtcodpy.LEFT)
    assert libtcodpy.console_get_alignment(console) == libtcodpy.LEFT

    libtcodpy.console_print(console, 0, 0, "print")
    libtcodpy.console_print_ex(console, 0, 0, libtcodpy.BKGND_SET, libtcodpy.LEFT, "print ex")

    assert libtcodpy.console_print_rect(console, 0, 0, 8, 8, "print rect") > 0
    assert (
        libtcodpy.console_print_rect_ex(console, 0, 0, 8, 8, libtcodpy.BKGND_SET, libtcodpy.LEFT, "print rect ex") > 0
    )
    assert libtcodpy.console_get_height_rect(console, 0, 0, 8, 8, "get height") > 0

    libtcodpy.console_set_color_control(libtcodpy.COLCTRL_1, fg, bg)


def test_console_printing_advanced(console):
    libtcodpy.console_rect(console, 0, 0, 4, 4, False, libtcodpy.BKGND_SET)
    libtcodpy.console_hline(console, 0, 0, 4)
    libtcodpy.console_vline(console, 0, 0, 4)
    libtcodpy.console_print_frame(console, 0, 0, 11, 11)


def test_console_fade(console):
    libtcodpy.console_set_fade(0, libtcodpy.Color(0, 0, 0))
    libtcodpy.console_get_fade()
    libtcodpy.console_get_fading_color()


def assertConsolesEqual(a, b):
    for y in range(libtcodpy.console_get_height(a)):
        for x in range(libtcodpy.console_get_width(a)):
            assert libtcodpy.console_get_char(a, x, y) == libtcodpy.console_get_char(b, x, y)
            assert libtcodpy.console_get_char_foreground(a, x, y) == libtcodpy.console_get_char_foreground(b, x, y)
            assert libtcodpy.console_get_char_background(a, x, y) == libtcodpy.console_get_char_background(b, x, y)


def test_console_blit(console, offscreen):
    libtcodpy.console_print(offscreen, 0, 0, "test")
    libtcodpy.console_blit(offscreen, 0, 0, 0, 0, console, 0, 0, 1, 1)
    assertConsolesEqual(console, offscreen)
    libtcodpy.console_set_key_color(offscreen, libtcodpy.black)


def test_console_asc_read_write(console, offscreen, tmpdir):
    libtcodpy.console_print(console, 0, 0, "test")

    asc_file = tmpdir.join("test.asc").strpath
    assert libtcodpy.console_save_asc(console, asc_file)
    assert libtcodpy.console_load_asc(offscreen, asc_file)
    assertConsolesEqual(console, offscreen)


def test_console_apf_read_write(console, offscreen, tmpdir):
    libtcodpy.console_print(console, 0, 0, "test")

    apf_file = tmpdir.join("test.apf").strpath
    assert libtcodpy.console_save_apf(console, apf_file)
    assert libtcodpy.console_load_apf(offscreen, apf_file)
    assertConsolesEqual(console, offscreen)


def test_console_rexpaint_load_test_file(console):
    xp_console = libtcodpy.console_from_xp("../data/rexpaint/test.xp")
    assert xp_console
    assert libtcodpy.console_get_char(xp_console, 0, 0) == ord("T")
    assert libtcodpy.console_get_char(xp_console, 1, 0) == ord("e")
    assert libtcodpy.console_get_char_background(xp_console, 0, 1) == libtcodpy.Color(255, 0, 0)
    assert libtcodpy.console_get_char_background(xp_console, 1, 1) == libtcodpy.Color(0, 255, 0)
    assert libtcodpy.console_get_char_background(xp_console, 2, 1) == libtcodpy.Color(0, 0, 255)


def test_console_rexpaint_save_load(console, tmpdir, ch, fg, bg):
    libtcodpy.console_print(console, 0, 0, "test")
    libtcodpy.console_put_char_ex(console, 1, 1, ch, fg, bg)
    xp_file = tmpdir.join("test.xp").strpath
    assert libtcodpy.console_save_xp(console, xp_file, 1)
    xp_console = libtcodpy.console_from_xp(xp_file)
    assert xp_console
    assertConsolesEqual(console, xp_console)
    assert libtcodpy.console_load_xp(None, xp_file)
    assertConsolesEqual(console, xp_console)


def test_console_rexpaint_list_save_load(console, tmpdir):
    con1 = libtcodpy.console_new(8, 2)
    con2 = libtcodpy.console_new(8, 2)
    libtcodpy.console_print(con1, 0, 0, "hello")
    libtcodpy.console_print(con2, 0, 0, "world")
    xp_file = tmpdir.join("test.xp").strpath
    assert libtcodpy.console_list_save_xp([con1, con2], xp_file, 1)
    for a, b in zip([con1, con2], libtcodpy.console_list_load_xp(xp_file)):
        assertConsolesEqual(a, b)
        libtcodpy.console_delete(a)
        libtcodpy.console_delete(b)


def test_console_fullscreen(console):
    libtcodpy.console_set_fullscreen(False)


def test_console_key_input(console):
    libtcodpy.console_check_for_keypress()
    libtcodpy.console_is_key_pressed(libtcodpy.KEY_ENTER)


def test_console_fill_errors(console):
    with pytest.raises(TypeError):
        libtcodpy.console_fill_background(console, [0], [], [])
    with pytest.raises(TypeError):
        libtcodpy.console_fill_foreground(console, [0], [], [])


def test_console_fill(console):
    width = libtcodpy.console_get_width(console)
    height = libtcodpy.console_get_height(console)
    fill = [i % 256 for i in range(width * height)]
    libtcodpy.console_fill_background(console, fill, fill, fill)
    libtcodpy.console_fill_foreground(console, fill, fill, fill)
    libtcodpy.console_fill_char(console, fill)

    # verify fill
    bg, fg, ch = [], [], []
    for y in range(height):
        for x in range(width):
            bg.append(libtcodpy.console_get_char_background(console, x, y)[0])
            fg.append(libtcodpy.console_get_char_foreground(console, x, y)[0])
            ch.append(libtcodpy.console_get_char(console, x, y))
    assert fill == bg
    assert fill == fg
    assert fill == ch


@unittest.skipUnless(numpy, "requires numpy module")
def test_console_fill_numpy(console):
    width = libtcodpy.console_get_width(console)
    height = libtcodpy.console_get_height(console)
    fill = numpy.zeros((height, width), dtype=numpy.intc)
    for y in range(height):
        fill[y, :] = y % 256

    libtcodpy.console_fill_background(console, fill, fill, fill)
    libtcodpy.console_fill_foreground(console, fill, fill, fill)
    libtcodpy.console_fill_char(console, fill)

    # verify fill
    bg = numpy.zeros((height, width), dtype=numpy.intc)
    fg = numpy.zeros((height, width), dtype=numpy.intc)
    ch = numpy.zeros((height, width), dtype=numpy.intc)
    for y in range(height):
        for x in range(width):
            bg[y, x] = libtcodpy.console_get_char_background(console, x, y)[0]
            fg[y, x] = libtcodpy.console_get_char_foreground(console, x, y)[0]
            ch[y, x] = libtcodpy.console_get_char(console, x, y)
    fill = fill.tolist()
    assert fill == bg.tolist()
    assert fill == fg.tolist()
    assert fill == ch.tolist()


def test_console_buffer(console):
    buffer = libtcodpy.ConsoleBuffer(
        libtcodpy.console_get_width(console),
        libtcodpy.console_get_height(console),
    )
    buffer = buffer.copy()
    buffer.set_fore(0, 0, 0, 0, 0, "@")
    buffer.set_back(0, 0, 0, 0, 0)
    buffer.set(0, 0, 0, 0, 0, 0, 0, 0, "@")
    buffer.blit(console)


def test_console_buffer_error(console):
    buffer = libtcodpy.ConsoleBuffer(0, 0)
    with pytest.raises(ValueError):
        buffer.blit(console)


def test_console_font_mapping(console):
    libtcodpy.console_map_ascii_code_to_font("@", 1, 1)
    libtcodpy.console_map_ascii_codes_to_font("@", 1, 0, 0)
    libtcodpy.console_map_string_to_font("@", 0, 0)


def test_mouse(console):
    libtcodpy.mouse_show_cursor(True)
    libtcodpy.mouse_is_cursor_visible()
    mouse = libtcodpy.mouse_get_status()
    repr(mouse)
    libtcodpy.mouse_move(0, 0)


def test_sys_time(console):
    libtcodpy.sys_set_fps(0)
    libtcodpy.sys_get_fps()
    libtcodpy.sys_get_last_frame_length()
    libtcodpy.sys_sleep_milli(0)
    libtcodpy.sys_elapsed_milli()
    libtcodpy.sys_elapsed_seconds()


def test_sys_screenshot(console, tmpdir):
    libtcodpy.sys_save_screenshot(tmpdir.join("test.png").strpath)


@pytest.mark.skip("not portable")
def test_sys_custom_render(console):
    escape = []

    def sdl_callback(sdl_surface):
        escape.append(True)
        libtcodpy.console_set_dirty(0, 0, 0, 0)

    libtcodpy.sys_register_SDL_renderer(sdl_callback)
    assert libtcodpy.console_flush() == 0
    assert escape, "proof that sdl_callback was called"


def test_image(console, tmpdir):
    img = libtcodpy.image_new(16, 16)
    libtcodpy.image_clear(img, libtcodpy.Color(0, 0, 0))
    libtcodpy.image_invert(img)
    libtcodpy.image_hflip(img)
    libtcodpy.image_rotate90(img)
    libtcodpy.image_vflip(img)
    libtcodpy.image_scale(img, 24, 24)
    libtcodpy.image_set_key_color(img, libtcodpy.Color(255, 255, 255))
    libtcodpy.image_get_alpha(img, 0, 0)
    libtcodpy.image_is_pixel_transparent(img, 0, 0)
    libtcodpy.image_get_size(img)
    libtcodpy.image_get_pixel(img, 0, 0)
    libtcodpy.image_get_mipmap_pixel(img, 0, 0, 1, 1)
    libtcodpy.image_put_pixel(img, 0, 0, libtcodpy.Color(255, 255, 255))
    libtcodpy.image_blit(img, console, 0, 0, libtcodpy.BKGND_SET, 1, 1, 0)
    libtcodpy.image_blit_rect(img, console, 0, 0, 16, 16, libtcodpy.BKGND_SET)
    libtcodpy.image_blit_2x(img, console, 0, 0)
    libtcodpy.image_save(img, tmpdir.join("test.png").strpath)
    libtcodpy.image_delete(img)

    # Not portable.
    # img = libtcodpy.image_from_console(console)
    # libtcodpy.image_refresh_console(img, console)
    # libtcodpy.image_delete(img)

    libtcodpy.image_delete(libtcodpy.image_load("../data/img/circle.png"))


@pytest.mark.skip("not portable")
@pytest.mark.parametrize("sample", ["@", u"\u2603"])  # Unicode snowman
def test_clipboard(console, sample):
    saved = libtcodpy.sys_clipboard_get()
    try:
        libtcodpy.sys_clipboard_set(sample)
        assert libtcodpy.sys_clipboard_get() == sample
    finally:
        libtcodpy.sys_clipboard_set(saved)


# arguments to test with and the results expected from these arguments
LINE_ARGS = (-5, 0, 5, 10)
EXCLUSIVE_RESULTS = [(-4, 1), (-3, 2), (-2, 3), (-1, 4), (0, 5), (1, 6), (2, 7), (3, 8), (4, 9), (5, 10)]
INCLUSIVE_RESULTS = [(-5, 0)] + EXCLUSIVE_RESULTS


def test_line_step():
    """
    libtcodpy.line_init and libtcodpy.line_step
    """
    libtcodpy.line_init(*LINE_ARGS)
    for expected_xy in EXCLUSIVE_RESULTS:
        assert libtcodpy.line_step() == expected_xy
    assert libtcodpy.line_step() == (None, None)


def test_line():
    """
    tests normal use, lazy evaluation, and error propagation
    """
    # test normal results
    test_result = []

    def line_test(*test_xy):
        test_result.append(test_xy)
        return 1

    assert libtcodpy.line(*LINE_ARGS, py_callback=line_test) == 1
    assert test_result == INCLUSIVE_RESULTS

    # test lazy evaluation
    test_result = []

    def return_false(*test_xy):
        test_result.append(test_xy)
        return False

    assert libtcodpy.line(*LINE_ARGS, py_callback=return_false) == 0
    assert test_result == INCLUSIVE_RESULTS[:1]


def test_line_iter():
    """
    libtcodpy.line_iter
    """
    assert list(libtcodpy.line_iter(*LINE_ARGS)) == INCLUSIVE_RESULTS


def test_bsp():
    """
    commented out statements work in libtcod-cffi
    """
    bsp = libtcodpy.bsp_new_with_size(0, 0, 64, 64)
    repr(bsp)  # test __repr__ on leaf
    libtcodpy.bsp_resize(bsp, 0, 0, 32, 32)
    assert bsp != None

    # test getter/setters
    bsp.x = bsp.x
    bsp.y = bsp.y
    bsp.w = bsp.w
    bsp.h = bsp.h
    bsp.position = bsp.position
    bsp.horizontal = bsp.horizontal
    bsp.level = bsp.level

    # cover functions on leaf
    # self.assertFalse(libtcodpy.bsp_left(bsp))
    # self.assertFalse(libtcodpy.bsp_right(bsp))
    # self.assertFalse(libtcodpy.bsp_father(bsp))
    assert libtcodpy.bsp_is_leaf(bsp)

    assert libtcodpy.bsp_contains(bsp, 1, 1)
    # self.assertFalse(libtcodpy.bsp_contains(bsp, -1, -1))
    # self.assertEqual(libtcodpy.bsp_find_node(bsp, 1, 1), bsp)
    # self.assertFalse(libtcodpy.bsp_find_node(bsp, -1, -1))

    libtcodpy.bsp_split_once(bsp, False, 4)
    repr(bsp)  # test __repr__ with parent
    libtcodpy.bsp_split_once(bsp, True, 4)
    repr(bsp)

    # cover functions on parent
    assert libtcodpy.bsp_left(bsp)
    assert libtcodpy.bsp_right(bsp)
    # self.assertFalse(libtcodpy.bsp_father(bsp))
    assert not libtcodpy.bsp_is_leaf(bsp)
    # self.assertEqual(libtcodpy.bsp_father(libtcodpy.bsp_left(bsp)), bsp)
    # self.assertEqual(libtcodpy.bsp_father(libtcodpy.bsp_right(bsp)), bsp)

    libtcodpy.bsp_split_recursive(bsp, None, 4, 2, 2, 1.0, 1.0)

    # cover bsp_traverse
    def traverse(node, user_data):
        return True

    libtcodpy.bsp_traverse_pre_order(bsp, traverse)
    libtcodpy.bsp_traverse_in_order(bsp, traverse)
    libtcodpy.bsp_traverse_post_order(bsp, traverse)
    libtcodpy.bsp_traverse_level_order(bsp, traverse)
    libtcodpy.bsp_traverse_inverted_level_order(bsp, traverse)

    # test __repr__ on deleted node
    son = libtcodpy.bsp_left(bsp)
    libtcodpy.bsp_remove_sons(bsp)
    repr(son)

    libtcodpy.bsp_delete(bsp)


def test_map():
    map = libtcodpy.map_new(16, 16)
    assert libtcodpy.map_get_width(map) == 16
    assert libtcodpy.map_get_height(map) == 16
    libtcodpy.map_copy(map, map)
    libtcodpy.map_clear(map)
    libtcodpy.map_set_properties(map, 0, 0, True, True)
    assert libtcodpy.map_is_transparent(map, 0, 0)
    assert libtcodpy.map_is_walkable(map, 0, 0)
    libtcodpy.map_is_in_fov(map, 0, 0)
    libtcodpy.map_delete(map)


def test_color():
    color_a = libtcodpy.Color(0, 1, 2)
    assert list(color_a) == [0, 1, 2]
    assert color_a[0] == color_a.r
    assert color_a[1] == color_a.g
    assert color_a[2] == color_a.b

    color_a[1] = 3
    color_a["b"] = color_a["b"]
    assert list(color_a) == [0, 3, 2]

    assert color_a == color_a

    color_b = libtcodpy.Color(255, 255, 255)
    assert color_a != color_b

    color = libtcodpy.color_lerp(color_a, color_b, 0.5)
    libtcodpy.color_set_hsv(color, 0, 0, 0)
    libtcodpy.color_get_hsv(color)
    libtcodpy.color_scale_HSV(color, 0, 0)


def test_color_repr():
    Color = libtcodpy.Color
    col = Color(0, 1, 2)
    assert eval(repr(col)) == col


def test_color_math():
    color_a = libtcodpy.Color(0, 1, 2)
    color_b = libtcodpy.Color(0, 10, 20)

    assert color_a + color_b == libtcodpy.Color(0, 11, 22)
    assert color_b - color_a == libtcodpy.Color(0, 9, 18)
    assert libtcodpy.Color(255, 255, 255) * color_a == color_a
    assert color_a * 100 == libtcodpy.Color(0, 100, 200)


def test_color_gen_map():
    colors = libtcodpy.color_gen_map([(0, 0, 0), (255, 255, 255)], [0, 8])
    assert colors[0] == libtcodpy.Color(0, 0, 0)
    assert colors[-1] == libtcodpy.Color(255, 255, 255)


def test_namegen_parse():
    libtcodpy.namegen_parse("../data/namegen/jice_celtic.cfg")
    assert libtcodpy.namegen_generate("Celtic female")
    assert libtcodpy.namegen_get_sets()
    libtcodpy.namegen_destroy()


def test_noise():
    noise = libtcodpy.noise_new(1)
    libtcodpy.noise_set_type(noise, libtcodpy.NOISE_SIMPLEX)
    libtcodpy.noise_get(noise, [0])
    libtcodpy.noise_get_fbm(noise, [0], 4)
    libtcodpy.noise_get_turbulence(noise, [0], 4)
    libtcodpy.noise_delete(noise)


def test_random():
    rand = libtcodpy.random_get_instance()
    rand = libtcodpy.random_new()
    libtcodpy.random_delete(rand)
    rand = libtcodpy.random_new_from_seed(42)
    libtcodpy.random_set_distribution(rand, libtcodpy.DISTRIBUTION_LINEAR)
    libtcodpy.random_get_int(rand, 0, 1)
    libtcodpy.random_get_int_mean(rand, 0, 1, 0)
    libtcodpy.random_get_float(rand, 0, 1)
    libtcodpy.random_get_double(rand, 0, 1)
    libtcodpy.random_get_float_mean(rand, 0, 1, 0)
    libtcodpy.random_get_double_mean(rand, 0, 1, 0)

    backup = libtcodpy.random_save(rand)
    libtcodpy.random_restore(rand, backup)

    libtcodpy.random_delete(rand)
    libtcodpy.random_delete(backup)


def test_heightmap():
    hmap = libtcodpy.heightmap_new(16, 16)
    repr(hmap)
    noise = libtcodpy.noise_new(2)

    # basic operations
    libtcodpy.heightmap_set_value(hmap, 0, 0, 1)
    libtcodpy.heightmap_add(hmap, 1)
    libtcodpy.heightmap_scale(hmap, 1)
    libtcodpy.heightmap_clear(hmap)
    libtcodpy.heightmap_clamp(hmap, 0, 0)
    libtcodpy.heightmap_copy(hmap, hmap)
    libtcodpy.heightmap_normalize(hmap)
    libtcodpy.heightmap_lerp_hm(hmap, hmap, hmap, 0)
    libtcodpy.heightmap_add_hm(hmap, hmap, hmap)
    libtcodpy.heightmap_multiply_hm(hmap, hmap, hmap)

    # modifying the heightmap
    libtcodpy.heightmap_add_hill(hmap, 0, 0, 4, 1)
    libtcodpy.heightmap_dig_hill(hmap, 0, 0, 4, 1)
    libtcodpy.heightmap_rain_erosion(hmap, 1, 1, 1)
    libtcodpy.heightmap_kernel_transform(hmap, 3, [-1, 1, 0], [0, 0, 0], [0.33, 0.33, 0.33], 0, 1)
    libtcodpy.heightmap_add_voronoi(hmap, 10, 3, [1, 3, 5])
    libtcodpy.heightmap_add_fbm(hmap, noise, 1, 1, 1, 1, 4, 1, 1)
    libtcodpy.heightmap_scale_fbm(hmap, noise, 1, 1, 1, 1, 4, 1, 1)
    libtcodpy.heightmap_dig_bezier(hmap, [0, 16, 16, 0], [0, 0, 16, 16], 1, 1, 1, 1)

    # read data
    libtcodpy.heightmap_get_value(hmap, 0, 0)
    libtcodpy.heightmap_get_interpolated_value(hmap, 0, 0)

    libtcodpy.heightmap_get_slope(hmap, 0, 0)
    libtcodpy.heightmap_get_normal(hmap, 0, 0, 0)
    libtcodpy.heightmap_count_cells(hmap, 0, 0)
    libtcodpy.heightmap_has_land_on_border(hmap, 0)
    libtcodpy.heightmap_get_minmax(hmap)

    libtcodpy.noise_delete(noise)
    libtcodpy.heightmap_delete(hmap)


MAP = (
    "############",
    "#   ###    #",
    "#   ###    #",
    "#   ### ####",
    "## #### # ##",
    "##      ####",
    "############",
)

MAP_WIDTH = len(MAP[0])
MAP_HEIGHT = len(MAP)

POINT_A = (2, 2)
POINT_B = (9, 2)
POINT_C = (9, 4)

POINTS_AB = POINT_A + POINT_B  # valid path
POINTS_AC = POINT_A + POINT_C  # invalid path


@pytest.fixture()
def map_():
    map_ = libtcodpy.map_new(MAP_WIDTH, MAP_HEIGHT)
    for y, line in enumerate(MAP):
        for x, ch in enumerate(line):
            libtcodpy.map_set_properties(map_, x, y, ch == " ", ch == " ")
    yield map_
    libtcodpy.map_delete(map_)


@pytest.fixture()
def path_callback(map_):
    def callback(ox, oy, dx, dy, user_data):
        if libtcodpy.map_is_walkable(map_, dx, dy):
            return 1
        return 0

    return callback


def test_map_fov(map_):
    libtcodpy.map_compute_fov(map_, *POINT_A)


def test_astar(map_):
    astar = libtcodpy.path_new_using_map(map_)

    assert not libtcodpy.path_compute(astar, *POINTS_AC)
    assert libtcodpy.path_size(astar) == 0
    assert libtcodpy.path_compute(astar, *POINTS_AB)
    assert libtcodpy.path_get_origin(astar) == POINT_A
    assert libtcodpy.path_get_destination(astar) == POINT_B
    libtcodpy.path_reverse(astar)
    assert libtcodpy.path_get_origin(astar) == POINT_B
    assert libtcodpy.path_get_destination(astar) == POINT_A

    assert libtcodpy.path_size(astar) != 0
    assert libtcodpy.path_size(astar) > 0
    assert not libtcodpy.path_is_empty(astar)

    for i in range(libtcodpy.path_size(astar)):
        x, y = libtcodpy.path_get(astar, i)

    while (x, y) != (None, None):
        x, y = libtcodpy.path_walk(astar, False)

    libtcodpy.path_delete(astar)


def test_astar_callback(map_, path_callback):
    astar = libtcodpy.path_new_using_function(
        libtcodpy.map_get_width(map_),
        libtcodpy.map_get_height(map_),
        path_callback,
    )
    libtcodpy.path_compute(astar, *POINTS_AB)
    libtcodpy.path_delete(astar)


def test_dijkstra(map_):
    path = libtcodpy.dijkstra_new(map_)

    libtcodpy.dijkstra_compute(path, *POINT_A)

    assert not libtcodpy.dijkstra_path_set(path, *POINT_C)
    assert libtcodpy.dijkstra_get_distance(path, *POINT_C) == -1

    assert libtcodpy.dijkstra_path_set(path, *POINT_B)
    assert libtcodpy.dijkstra_size(path)
    assert not libtcodpy.dijkstra_is_empty(path)

    libtcodpy.dijkstra_reverse(path)

    for i in range(libtcodpy.dijkstra_size(path)):
        x, y = libtcodpy.dijkstra_get(path, i)

    while (x, y) != (None, None):
        x, y = libtcodpy.dijkstra_path_walk(path)

    libtcodpy.dijkstra_delete(path)


def test_dijkstra_callback(map_, path_callback):
    path = libtcodpy.dijkstra_new_using_function(
        libtcodpy.map_get_width(map_),
        libtcodpy.map_get_height(map_),
        path_callback,
    )
    libtcodpy.dijkstra_compute(path, *POINT_A)
    libtcodpy.dijkstra_delete(path)


if __name__ == "__main__":
    pytest.main()