#include "assets/image_format.h"
#include "test_harness.h"

#include <array>
#include <cstddef>
#include <string_view>

using pp::assets::ImageFormat;
using pp::assets::detect_image_format;
using pp::assets::image_format_name;
using pp::foundation::StatusCode;

namespace {

void detects_png_and_jpeg_signatures(pp::tests::Harness& h)
{
    constexpr std::array png {
        std::byte { 0x89 },
        std::byte { 0x50 },
        std::byte { 0x4e },
        std::byte { 0x47 },
        std::byte { 0x0d },
        std::byte { 0x0a },
        std::byte { 0x1a },
        std::byte { 0x0a },
        std::byte { 0x00 },
    };
    constexpr std::array jpeg {
        std::byte { 0xff },
        std::byte { 0xd8 },
        std::byte { 0xff },
        std::byte { 0xe0 },
    };

    const auto png_format = detect_image_format(png);
    const auto jpeg_format = detect_image_format(jpeg);

    PP_EXPECT(h, png_format.ok());
    PP_EXPECT(h, png_format.value() == ImageFormat::png);
    PP_EXPECT(h, image_format_name(png_format.value()) == std::string_view("png"));
    PP_EXPECT(h, jpeg_format.ok());
    PP_EXPECT(h, jpeg_format.value() == ImageFormat::jpeg);
    PP_EXPECT(h, image_format_name(jpeg_format.value()) == std::string_view("jpeg"));
}

void rejects_empty_truncated_and_unsupported_inputs(pp::tests::Harness& h)
{
    constexpr std::array<std::byte, 0> empty {};
    constexpr std::array partial_png {
        std::byte { 0x89 },
        std::byte { 0x50 },
        std::byte { 0x4e },
    };
    constexpr std::array short_unknown {
        std::byte { 0x12 },
        std::byte { 0x34 },
    };
    constexpr std::array unsupported {
        std::byte { 0x47 },
        std::byte { 0x49 },
        std::byte { 0x46 },
        std::byte { 0x38 },
    };

    const auto empty_result = detect_image_format(empty);
    const auto partial_png_result = detect_image_format(partial_png);
    const auto short_result = detect_image_format(short_unknown);
    const auto unsupported_result = detect_image_format(unsupported);

    PP_EXPECT(h, !empty_result.ok());
    PP_EXPECT(h, empty_result.status().code == StatusCode::invalid_argument);
    PP_EXPECT(h, !partial_png_result.ok());
    PP_EXPECT(h, partial_png_result.status().code == StatusCode::out_of_range);
    PP_EXPECT(h, !short_result.ok());
    PP_EXPECT(h, short_result.status().code == StatusCode::out_of_range);
    PP_EXPECT(h, !unsupported_result.ok());
    PP_EXPECT(h, unsupported_result.status().code == StatusCode::invalid_argument);
}

}

int main()
{
    pp::tests::Harness harness;
    harness.run("detects_png_and_jpeg_signatures", detects_png_and_jpeg_signatures);
    harness.run("rejects_empty_truncated_and_unsupported_inputs", rejects_empty_truncated_and_unsupported_inputs);
    return harness.finish();
}
