void test_train_crashes_by_occupying_same_tile(test_train_context* test_ctx, const void* data) { #pragma unused(data) sem_train* train1 = test_ctx->train1; sem_train* train2 = test_ctx->train2; sem_world* world = &(test_ctx->world); sem_track trackW_E; sem_track_set(&trackW_E, SEM_WEST, SEM_EAST); sem_tile* tile = sem_tile_at(world, 1, 0); sem_tile_set_track(tile, &trackW_E); train1->state = MOVING; train1->direction = SEM_EAST; sem_car train1_car; sem_coordinate_set(&(train1_car.position), 0, 0); sem_train_add_car(train1, &train1_car); train2->state = STOPPED; sem_car train2_car1; sem_coordinate_set(&(train2_car1.position), 1, 0); sem_train_add_car(train2, &train2_car1); sem_car train2_car2; sem_coordinate_set(&(train2_car2.position), 2, 0); sem_train_add_car(train2, &train2_car2); sem_train_move_outcome outcome; sem_train_move(train1, &outcome); // move head of train1 into tail of train2 g_assert_true(train1->state == CRASHED); g_assert_true(train2->state == CRASHED); }
void test_train_moves_head_car(test_train_context* test_ctx, const void* data) { #pragma unused(data) sem_world* world = &(test_ctx->world); sem_train* train = test_ctx->train; sem_car head_car; sem_coordinate_set(&(head_car.position), 1, 0); sem_train_add_car(train, &head_car); sem_car car2; sem_coordinate_set(&(car2.position), 0, 0); sem_train_add_car(train, &car2); train->direction = SEM_EAST; sem_track track_E_W; sem_track_set(&track_E_W, SEM_EAST, SEM_WEST); sem_tile_set_track(sem_tile_at(world, 0, 0), &track_E_W); sem_tile_set_track(sem_tile_at(world, 1, 0), &track_E_W); sem_tile_set_track(sem_tile_at(world, 2, 0), &track_E_W); sem_train_move_outcome outcome; sem_train_move(train, &outcome); g_assert_cmpuint(train->position->x, ==, 2); g_assert_cmpuint(train->position->y, ==, 0); }
void test_portal_train_exits_into_portal(test_portal_context* test_ctx, const void* data) { #pragma unused(data) sem_world* world = &(test_ctx->game.world); sem_train* train = malloc(sizeof(sem_train)); sem_train_init(train); train->state = MOVING; train->direction = SEM_EAST; sem_world_add_train(world, train); sem_car* tail_car = malloc(sizeof(sem_car)); sem_coordinate_set(&(tail_car->position), 1, 0); tail_car->track = sem_tile_at(world, 1, 0)->track; sem_car* head_car = malloc(sizeof(sem_car)); sem_coordinate_set(&(head_car->position), 2, 0); head_car->track = sem_tile_at(world, 2, 0)->track; sem_train_add_car(train, head_car); sem_train_add_car(train, tail_car); sem_action action; action.time = 2000; action.game = &(test_ctx->game); action.context = train; action.function = sem_move_train_action; action.dynamically_allocated = false; g_assert_true(sem_move_train_action(world->actions, &action) == SEM_OK); sem_action* move_action = sem_heap_remove_earliest(world->actions); g_assert_nonnull(move_action); g_assert_true(move_action->function(world->actions, move_action) == SEM_OK); g_assert_cmpuint(train->cars, ==, 1); g_assert_cmpuint(train->position->x, ==, 3); g_assert_cmpuint(train->position->y, ==, 0); move_action = sem_heap_remove_earliest(world->actions); g_assert_nonnull(move_action); g_assert_true(move_action->function(world->actions, move_action) == SEM_OK); sem_action* train_exit_action = sem_heap_remove_earliest(world->actions); g_assert_nonnull(train_exit_action); train_exit_action->function(world->actions, move_action); g_assert_cmpuint(world->trains->tail_idx, ==, 0); }
void test_train_stops_at_buffer(test_train_context* test_ctx, const void* data) { #pragma unused(data) sem_train* train = test_ctx->train; sem_world* world = &(test_ctx->world); sem_track trackE_W; sem_track_set(&trackE_W, SEM_EAST, SEM_WEST); sem_tile_set_track(sem_tile_at(world, 0, 0), &trackE_W); sem_tile_set_buffer(sem_tile_at(world, 1, 0), &trackE_W); sem_car car; sem_coordinate_set(&(car.position), 0, 0); car.track = &trackE_W; sem_train_add_car(train, &car); train->direction = SEM_EAST; train->state = MOVING; sem_train_move_outcome outcome; sem_train_move(train, &outcome); g_assert_true(train->state == STOPPED); g_assert_cmpuint(train->position->x, ==, 0); g_assert_cmpuint(train->position->y, ==, 0); g_assert_true(outcome.stopped_at_buffer == true); }
void test_train_derails_when_need_points_switch(test_train_context* test_ctx, const void* data) { #pragma unused(data) sem_train* train = test_ctx->train; sem_world* world = &(test_ctx->world); sem_tile_acceptance acceptance; sem_tile_acceptance_init(&acceptance); train->direction = SEM_EAST; sem_car car; sem_coordinate_set(&(car.position), 0, 0); sem_train_add_car(train, &car); sem_track trackNW_E; sem_track_set(&trackNW_E, SEM_NORTH | SEM_WEST, SEM_EAST); sem_track trackW_E; sem_track_set(&trackW_E, SEM_WEST, SEM_EAST); sem_tile* tile = sem_tile_at(world, 1, 0); sem_tile_set_points(tile, &trackNW_E); tile->points[1] = &trackW_E; sem_train_move_outcome outcome; sem_train_move(train, &outcome); g_assert_true(train->state == DERAILED); }
void test_train_car_occupies_track(test_train_context* test_ctx, const void* data) { #pragma unused(data) sem_world* world = &(test_ctx->world); sem_train* train = test_ctx->train; sem_track track_E_W; sem_track_set(&track_E_W, SEM_EAST, SEM_WEST); sem_track track_W_S; sem_track_set(&track_W_S, SEM_WEST, SEM_SOUTH); sem_tile_set_track(sem_tile_at(world, 0, 0), &track_E_W); sem_tile_set_track(sem_tile_at(world, 1, 0), &track_W_S); train->state = MOVING; train->direction = SEM_EAST; sem_car car; sem_coordinate_set(&(car.position), 0, 0); car.track = &track_E_W; sem_train_add_car(train, &car); sem_train_move_outcome outcome; sem_train_move(train, &outcome); g_assert_true(train->head_car->track == &track_W_S); }
void test_train_second_car_occupies_tile(test_train_context* test_ctx, const void* data) { #pragma unused(data) sem_train* train = test_ctx->train; sem_car head_car; sem_coordinate_set(&(head_car.position), 2, 0); sem_train_add_car(train, &head_car); sem_coordinate second_car_position; sem_coordinate_set(&second_car_position, 1, 0); sem_car second_car; second_car.position = second_car_position; sem_train_add_car(train, &second_car); g_assert_true(sem_train_occupies(train, &second_car_position)); }
void test_train_follows_secondary_track(test_train_context* test_ctx, const void* data) { #pragma unused(data) sem_world* world = &(test_ctx->world); sem_train* train = test_ctx->train; sem_car car; sem_coordinate_set(&(car.position), 0, 0); sem_train_add_car(train, &car); train->direction = SEM_EAST; sem_track track_E_W; sem_track_set(&track_E_W, SEM_EAST, SEM_WEST); sem_track track_SE_W; sem_track_set(&track_SE_W, SEM_SOUTH | SEM_EAST, SEM_WEST); sem_track track_N_S_SE_W; sem_track_set(&track_N_S_SE_W, SEM_NORTH, SEM_SOUTH); track_N_S_SE_W.next = &track_SE_W; sem_tile_set_track(sem_tile_at(world, 0, 0), &track_E_W); sem_tile_set_track(sem_tile_at(world, 1, 0), &track_N_S_SE_W); sem_train_move_outcome outcome; g_assert_true(sem_train_move(train, &outcome) == SEM_OK); g_assert_true(train->direction == (SEM_SOUTH | SEM_EAST)); }
void test_portal_revenue_when_train_exits_portal(test_portal_context* test_ctx, sem_coordinate* exit, int32_t expected_balance) { sem_game* game = &(test_ctx->game); sem_world* world = &(test_ctx->game.world); sem_train* train = malloc(sizeof(sem_train)); sem_train_init(train); train->state = MOVING; train->direction = SEM_EAST; train->has_exit_position = (exit != NULL); if (train->has_exit_position) train->exit_position = *exit; sem_world_add_train(world, train); sem_car* head_car = malloc(sizeof(sem_car)); sem_coordinate_set(&(head_car->position), 2, 0); head_car->track = sem_tile_at(world, 2, 0)->track; sem_train_add_car(train, head_car); sem_action action; action.time = 2000; action.game = &(test_ctx->game); action.context = train; action.function = sem_move_train_action; action.dynamically_allocated = false; sem_move_train_action(world->actions, &action); sem_action* move_action = sem_heap_remove_earliest(world->actions); move_action->function(world->actions, move_action); sem_action* train_exit_action = sem_heap_remove_earliest(world->actions); train_exit_action->function(world->actions, move_action); g_assert_cmpint(game->revenue.balance, ==, expected_balance); }
void test_train_reverses(test_train_context* test_ctx, const void* data) { #pragma unused(data) sem_train* train = test_ctx->train; sem_world* world = &(test_ctx->world); sem_tile* tile = sem_tile_at(world, 1, 1); sem_track trackS_NE; sem_track_set(&trackS_NE, SEM_SOUTH, SEM_NORTH | SEM_EAST); sem_tile_set_track(tile, &trackS_NE); sem_track trackSW_E; sem_track_set(&trackSW_E, SEM_SOUTH | SEM_WEST, SEM_EAST); sem_tile_set_track(sem_tile_at(world, 2, 0), &trackSW_E); sem_track trackW_E; sem_track_set(&trackW_E, SEM_WEST, SEM_EAST); sem_tile_set_track(sem_tile_at(world, 3, 0), &trackW_E); train->direction = SEM_EAST; sem_car car1; sem_coordinate_set(&(car1.position), 3, 0); car1.track = &trackSW_E; sem_train_add_car(train, &car1); sem_car car2; sem_coordinate_set(&(car2.position), 2, 0); car2.track = &trackSW_E; sem_train_add_car(train, &car2); sem_car car3; sem_coordinate_set(&(car3.position), 1, 1); car3.track = &trackS_NE; sem_train_add_car(train, &car3); sem_train_reverse(train); g_assert_true(train->head_car == &car3); g_assert_true(train->head_car->next == &car2); g_assert_true(train->head_car->next->next == &car1); g_assert_true(train->tail_car == &car1); g_assert_true(train->direction == SEM_SOUTH); g_assert_cmpuint(train->position->x, ==, 1); g_assert_cmpuint(train->position->y, ==, 1); }
void test_train_removes_head_car(test_train_context* test_ctx, const void* data) { #pragma unused(data) sem_train* train = test_ctx->train; sem_car* tail_car = malloc(sizeof(sem_car)); sem_coordinate_set(&(tail_car->position), 0, 0); sem_car* head_car = malloc(sizeof(sem_car)); sem_coordinate_set(&(head_car->position), 1, 0); sem_train_add_car(train, head_car); sem_train_add_car(train, tail_car); sem_train_remove_head_car(train); g_assert_cmpuint(train->cars, ==, 1); g_assert_true(train->head_car == tail_car); g_assert_cmpuint(train->position->x, ==, 0); g_assert_cmpuint(train->position->y, ==, 0); g_assert_true(train->headless); }
void test_train_not_occupies_tile(test_train_context* test_ctx, const void* data) { #pragma unused(data) sem_train* train = test_ctx->train; sem_coordinate head_position; sem_coordinate_set(&head_position, 2, 0); sem_car head_car; head_car.position = head_position; sem_train_add_car(train, &head_car); sem_coordinate other_tile; sem_coordinate_set(&other_tile, 1, 1); g_assert_false(sem_train_occupies(train, &other_tile)); }
void test_train_error_moves_onto_blank_tile(test_train_context* test_ctx, const void* data) { #pragma unused(data) sem_world* world = &(test_ctx->world); sem_train* train = test_ctx->train; sem_car car; sem_coordinate_set(&(car.position), 0, 0); sem_train_add_car(train, &car); train->direction = SEM_EAST; sem_track track_E_W; sem_track_set(&track_E_W, SEM_EAST, SEM_WEST); sem_tile_set_track(sem_tile_at(world, 0, 0), &track_E_W); sem_train_move_outcome outcome; g_assert_cmpint(sem_train_move(train, &outcome), ==, SEM_ERROR); }
void test_train_moves_given_velocity(test_train_context* test_ctx, const void* data) { #pragma unused(data) sem_world* world = &(test_ctx->world); sem_train* train = test_ctx->train; sem_car car; sem_coordinate_set(&(car.position), 0, 1); sem_train_add_car(train, &car); train->direction = SEM_NORTH | SEM_EAST; sem_track track_SW_NE; sem_track_set(&track_SW_NE, SEM_SOUTH | SEM_WEST, SEM_NORTH | SEM_EAST); sem_tile_set_track(sem_tile_at(world, 1, 0), &track_SW_NE); sem_train_move_outcome outcome; sem_train_move(train, &outcome); g_assert_cmpuint(train->position->x, ==, 1); g_assert_cmpuint(train->position->y, ==, 0); }
void test_serialize_save_load_train() { sem_world world; world.max_x = 3; world.max_y = 2; sem_world_init_blank(&world); sem_tile* tile = sem_tile_at(&world, 0, 1); sem_track trackW_E; sem_track_set(&trackW_E, SEM_WEST, SEM_EAST); sem_tile_set_track(tile, &trackW_E); tile = sem_tile_at(&world, 1, 1); sem_track trackN_S_W_E; sem_track_set(&trackN_S_W_E, SEM_NORTH, SEM_SOUTH); trackN_S_W_E.next = &trackW_E; sem_tile_set_track(tile, &trackN_S_W_E); sem_train* saved_train1 = malloc(sizeof(sem_train)); sem_train* train1 = saved_train1; sem_train_init(train1); train1->direction = SEM_EAST; train1->name = strdup("IC-123"); sem_car car1; sem_coordinate_set(&(car1.position), 1, 1); car1.track = &trackW_E; sem_train_add_car(train1, &car1); sem_car car2; sem_coordinate_set(&(car2.position), 0, 1); car2.track = &trackW_E; sem_train_add_car(train1, &car2); sem_world_add_train(&world, train1); sem_train* saved_train2 = malloc(sizeof(sem_train)); sem_train* train2 = saved_train2; sem_train_init(train2); train2->direction = SEM_WEST; train2->state = DERAILED; sem_world_add_train(&world, train2); FILE* file = save_and_load("build/test/train", &world); g_assert_cmpuint(world.trains->tail_idx, ==, 2); train1 = world.trains->items[0]; g_assert_true(train1->state == STOPPED); g_assert_true(train1->direction == SEM_EAST); g_assert_cmpuint(train1->cars, ==, 2); g_assert_cmpstr(train1->name, ==, "IC-123"); sem_car* car = train1->head_car; g_assert_cmpuint(car->position.x, ==, 1); g_assert_cmpuint(car->position.y, ==, 1); sem_track* track = car->track; g_assert_true(track->start == SEM_WEST); g_assert_true(track->end == SEM_EAST); train2 = world.trains->items[1]; g_assert_true(train2->state == DERAILED); g_assert_true(train2->direction == SEM_WEST); sem_world_destroy(&world); fclose(file); }
void test_serialize_load_remove_train_action() { sem_world world; world.max_x = 3; world.max_y = 1; sem_world_init_blank(&world); sem_tile* tile = sem_tile_at(&world, 0, 0); sem_track trackW_E; sem_track_set(&trackW_E, SEM_WEST, SEM_EAST); sem_tile_set_track(tile, &trackW_E); tile = sem_tile_at(&world, 2, 0); sem_track trackN_S; sem_track_set(&trackN_S, SEM_NORTH, SEM_SOUTH); sem_tile_set_track(tile, &trackN_S); sem_train* train1 = malloc(sizeof(sem_train)); sem_train_init(train1); uuid_t train1_id; uuid_copy(train1->id, train1_id); train1->direction = SEM_NORTH; sem_car car1; sem_coordinate_set(&(car1.position), 2, 0); car1.track = &trackN_S; sem_train_add_car(train1, &car1); sem_world_add_train(&world, train1); sem_train* train2 = malloc(sizeof(sem_train)); sem_train_init(train2); train2->state = DERAILED; train2->direction = SEM_EAST; sem_car car2; sem_coordinate_set(&(car2.position), 0, 0); car2.track = &trackW_E; sem_train_add_car(train2, &car2); sem_world_add_train(&world, train2); // TODO: should fetch a partially-initialised sem_action from // a factory method sem_action action; action.time = 5000; action.function = remove_train_action; action.write = sem_remove_train_action_write; action.context = train2; sem_heap_insert(world.actions, &action); FILE* file = save_and_load("build/test/remove_train_action", &world); sem_action* loaded_action = sem_heap_remove_earliest(world.actions); g_assert_false(loaded_action == NULL); g_assert_true(loaded_action->function(world.actions, loaded_action) == SEM_OK); g_assert_cmpuint(world.trains->tail_idx, ==, 1); sem_train* remaining_train = (sem_train*) world.trains->items[0]; g_assert_true(uuid_compare(remaining_train->id, train1_id) == 0); sem_world_destroy(&world); fclose(file); }