#include "ipu_image.hpp"
#include "ipu_image_writer.hpp"

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

int main() try {
  const std::string path = "/tmp/ipu_image_tests.ipuimg";
  std::vector<std::vector<std::uint8_t>> expected(
      4, std::vector<std::uint8_t>(257));
  for (unsigned tile = 0; tile < expected.size(); ++tile)
    for (unsigned i = 0; i < expected[tile].size(); ++i)
      expected[tile][i] = static_cast<std::uint8_t>(i * 17 + tile * 29);
  expected[0] = expected[2];
  expected[1][0] ^= 0x80;
  expected[3][256] ^= 0x40;

  ipuimg::write(path, expected, 0x4c000, 0x4c010, 2);
  ipuimg::Image image(path);
  if (image.header().tileCount != expected.size() ||
      image.header().baseAddress != 0x4c000 ||
      image.header().entryPoint != 0x4c010)
    throw std::runtime_error("header mismatch");
  for (unsigned tile = 0; tile < expected.size(); ++tile)
    if (image.tile(tile) != expected[tile])
      throw std::runtime_error("round-trip mismatch");

  std::fstream corrupt(path, std::ios::binary | std::ios::in | std::ios::out);
  corrupt.seekg(-1, std::ios::end);
  char byte;
  corrupt.read(&byte, 1);
  corrupt.clear();
  corrupt.seekp(-1, std::ios::end);
  byte ^= 1;
  corrupt.write(&byte, 1);
  corrupt.close();
  bool rejected = false;
  try {
    ipuimg::Image damaged(path);
    (void)damaged.tile(3);
  } catch (const std::runtime_error &) {
    rejected = true;
  }
  std::remove(path.c_str());
  if (!rejected) throw std::runtime_error("corruption was not rejected");
  std::cout << "ipu_image_tests: PASS\n";
  return 0;
} catch (const std::exception &error) {
  std::cerr << "ipu_image_tests: " << error.what() << '\n';
  return 1;
}
