#include "host_exchange.hpp"

#include <cstdio>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <string>

namespace {
void write(const std::string &path, const std::string &contents) {
  std::ofstream output(path);
  output << contents;
  if (!output)
    throw std::runtime_error("cannot write test manifest");
}
} // namespace

int main() try {
  const std::string path = "/tmp/host_exchange_tests.ipuhsp";
  write(path,
        "IPU-HOST-EXCHANGE 1\n"
        "startup-mark 7\n"
        "page 3 256\n"
        "page 9 128\n"
        "attach 9\n"
        "attach 3\n"
        "command 9 12\n"
        "call mixed 42 5\n"
        "input mixed 3 32 4 16\n"
        "input mixed 3 64 20 8\n"
        "output mixed 9 32 8 24\n");
  const auto protocol = hostexchange::Protocol::read(path);
  const auto &call = protocol.call("mixed");
  if (protocol.startupMark != 7 || protocol.pages.size() != 2 ||
      protocol.attachOrder[0] != 9 || protocol.commandPage != 9 ||
      protocol.commandOffset != 12 || call.id != 42 || call.phases != 5 ||
      protocol.inputSize(call) != 28 || protocol.outputSize(call) != 32)
    throw std::runtime_error("parsed manifest differs from input");

  write(path,
        "IPU-HOST-EXCHANGE 1\n"
        "startup-mark 1\n"
        "page 0 16\n"
        "attach 0\n"
        "command 0 14\n");
  bool rejected = false;
  try {
    (void)hostexchange::Protocol::read(path);
  } catch (const std::runtime_error &) {
    rejected = true;
  }
  std::remove(path.c_str());
  if (!rejected)
    throw std::runtime_error("out-of-range command was accepted");
  std::cout << "host_exchange_tests: PASS\n";
  return 0;
} catch (const std::exception &error) {
  std::cerr << "host_exchange_tests: " << error.what() << '\n';
  return 1;
}
