/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2018, Google Inc.
 *
 * byte_stream_buffer.cpp - ByteStreamBuffer tests
 */

#include <array>
#include <iostream>

#include "libcamera/internal/byte_stream_buffer.h"

#include "test.h"

using namespace std;
using namespace libcamera;

class ByteStreamBufferTest : public Test
{
protected:
	int run()
	{
		/*
		 * gcc 11.1.0 incorrectly raises a maybe-uninitialized warning
		 * when calling data.size() below (if the address sanitizer is
		 * disabled). Silence it by initializing the array.
		 */
		std::array<uint8_t, 100> data = {};
		unsigned int i;
		uint32_t value;
		int ret;

		/*
		 * Write mode.
		 */
		ByteStreamBuffer wbuf(data.data(), data.size());

		if (wbuf.base() != data.data() || wbuf.size() != data.size() ||
		    wbuf.offset() != 0 || wbuf.overflow()) {
			cerr << "Write buffer incorrectly constructed" << endl;
			return TestFail;
		}

		/* Test write. */
		value = 0x12345678;
		ret = wbuf.write(&value);
		if (ret || wbuf.offset() != 4 || wbuf.overflow() ||
		    *reinterpret_cast<uint32_t *>(data.data()) != 0x12345678) {
			cerr << "Write failed on write buffer" << endl;
			return TestFail;
		}

		/* Test write carve out. */
		ByteStreamBuffer wco = wbuf.carveOut(10);
		if (wco.base() != wbuf.base() + 4 || wco.size() != 10 ||
		    wco.offset() != 0 || wco.overflow() || wbuf.offset() != 14 ||
		    wbuf.overflow()) {
			cerr << "Carving out write buffer failed" << endl;
			return TestFail;
		}

		/* Test write on the carved out buffer. */
		value = 0x87654321;
		ret = wco.write(&value);
		if (ret || wco.offset() != 4 || wco.overflow() ||
		    *reinterpret_cast<uint32_t *>(data.data() + 4) != 0x87654321) {
			cerr << "Write failed on carve out buffer" << endl;
			return TestFail;
		}

		if (wbuf.offset() != 14 || wbuf.overflow()) {
			cerr << "Write on carve out buffer modified write buffer" << endl;
			return TestFail;
		}

		/* Test read, this should fail. */
		ret = wbuf.read(&value);
		if (!ret || wbuf.overflow()) {
			cerr << "Read should fail on write buffer" << endl;
			return TestFail;
		}

		/* Test overflow on carved out buffer. */
		for (i = 0; i < 2; ++i) {
			ret = wco.write(&value);
			if (ret < 0)
				break;
		}

		if (i != 1 || !wco.overflow() || !wbuf.overflow()) {
			cerr << "Write on carve out buffer failed to overflow" << endl;
			return TestFail;
		}

		/* Test reinitialization of the buffer. */
		wbuf = ByteStreamBuffer(data.data(), data.size());
		if (wbuf.overflow() || wbuf.base() != data.data() ||
		    wbuf.offset() != 0) {
			cerr << "Write buffer reinitialization failed" << endl;
			return TestFail;
		}

		/*
		 * Read mode.
		 */
		ByteStreamBuffer rbuf(const_cast<const uint8_t *>(data.data()),
				      data.size());

		if (rbuf.base() != data.data() || rbuf.size() != data.size() ||
		    rbuf.offset() != 0 || rbuf.overflow()) {
			cerr << "Read buffer incorrectly constructed" << endl;
			return TestFail;
		}

		/* Test read. */
		value = 0;
		ret = rbuf.read(&value);
		if (ret || rbuf.offset() != 4 || rbuf.overflow() ||
		    value != 0x12345678) {
			cerr << "Write failed on write buffer" << endl;
			return TestFail;
		}

		/* Test read carve out. */
		ByteStreamBuffer rco = rbuf.carveOut(10);
		if (rco.base() != rbuf.base() + 4 || rco.size() != 10 ||
		    rco.offset() != 0 || rco.overflow() || rbuf.offset() != 14 ||
		    rbuf.overflow()) {
			cerr << "Carving out read buffer failed" << endl;
			return TestFail;
		}

		/* Test read on the carved out buffer. */
		value = 0;
		ret = rco.read(&value);
		if (ret || rco.offset() != 4 || rco.overflow() || value != 0x87654321) {
			cerr << "Read failed on carve out buffer" << endl;
			return TestFail;
		}

		if (rbuf.offset() != 14 || rbuf.overflow()) {
			cerr << "Read on carve out buffer modified read buffer" << endl;
			return TestFail;
		}

		/* Test write, this should fail. */
		ret = rbuf.write(&value);
		if (!ret || rbuf.overflow()) {
			cerr << "Write should fail on read buffer" << endl;
			return TestFail;
		}

		/* Test overflow on carved out buffer. */
		for (i = 0; i < 2; ++i) {
			ret = rco.read(&value);
			if (ret < 0)
				break;
		}

		if (i != 1 || !rco.overflow() || !rbuf.overflow()) {
			cerr << "Read on carve out buffer failed to overflow" << endl;
			return TestFail;
		}

		/* Test reinitialization of the buffer. */
		rbuf = ByteStreamBuffer(const_cast<const uint8_t *>(data.data()),
					data.size());
		if (rbuf.overflow() || rbuf.base() != data.data() ||
		    rbuf.offset() != 0) {
			cerr << "Read buffer reinitialization failed" << endl;
			return TestFail;
		}

		return TestPass;
	}
};

TEST_REGISTER(ByteStreamBufferTest)
