// SPDX-License-Identifier: LGPL-3.0-or-later
// Copyright © 2020-2021 Florian Fischer
#include <sys/eventfd.h>	// for eventfd, EFD_SEMAPHORE

#include <cassert>	// for assert
#include <cerrno>		// for ECANCELED, ETIME
#include <cstdint>	// for uint64_t, int32_t

#include "Common.hpp"			// for DIE_MSG_ERRNO
#include "io/Future.hpp"	// for ReadFuture, WriteFuture

using emper::io::ReadFuture;
using emper::io::WriteFuture;

void emperTest() {
	int efd = eventfd(0, 0);
	if (efd == -1) {
		DIE_MSG_ERRNO("eventfd failed");
	}

	uint64_t read_buf;
	uint64_t write_buf = 42;
	// cancel not submitted Future
	ReadFuture readFuture(efd, &read_buf, sizeof(read_buf), 0);
	assert(readFuture.cancel() == -ENOENT);

	// cancel submitted non-completed Future
	readFuture.submit();
	assert(readFuture.cancel() == -ECANCELED);

	readFuture.reset();

	readFuture.submit();
	WriteFuture writeFuture(efd, &write_buf, sizeof(write_buf), 0);
	assert(writeFuture.submitAndWait() == sizeof(write_buf));
	assert(readFuture.cancel() == sizeof(write_buf) && read_buf == write_buf);

	writeFuture.reset();
	read_buf = 0;
	readFuture.reset();

	// cancel a chain
	ReadFuture readFuture2(efd, &read_buf, sizeof(read_buf), 0);
	readFuture2.setDependency(readFuture);
	readFuture2.submit();
	assert(readFuture2.cancel() == -ECANCELED);
	assert(readFuture.wait() == -ECANCELED);

	readFuture2.reset();
	readFuture.reset();

	// cancel partial completed chain
	readFuture2.submit();
	assert(writeFuture.submitAndWait() == sizeof(write_buf));
	// TODO: investigate why this read is completed with -EINTR most of the time
	int r = readFuture2.cancel();
	assert(r == -EINTR || r == -ECANCELED);
	assert(readFuture.wait() == sizeof(write_buf) && read_buf == write_buf);
}