// Copyright 2019 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <vector>

#include "public/fpdf_thumbnail.h"
#include "public/fpdfview.h"
#include "testing/embedder_test.h"
#include "testing/utils/hash.h"

namespace {

const char kSimpleThumbnailChecksum[] = "f6a8e8db01cccd52abb91ea433a17373";
const char kThumbnailWithNoFiltersChecksum[] =
    "b5696e586382b3373741f8a1d651cab0";

}  // namespace

class FPDFThumbnailEmbedderTest : public EmbedderTest {};

TEST_F(FPDFThumbnailEmbedderTest, GetDecodedThumbnailDataFromPageWithFilters) {
  ASSERT_TRUE(OpenDocument("simple_thumbnail.pdf"));

  {
    const char kHashedDecodedData[] = "7902d0be831c9024960f4ebd5d7df1f7";
    const unsigned long kExpectedSize = 1138u;

    ScopedPage page = LoadScopedPage(0);
    ASSERT_TRUE(page);

    unsigned long length_bytes =
        FPDFPage_GetDecodedThumbnailData(page.get(), nullptr, 0);
    ASSERT_EQ(kExpectedSize, length_bytes);
    std::vector<uint8_t> thumb_buf(length_bytes);

    EXPECT_EQ(kExpectedSize, FPDFPage_GetDecodedThumbnailData(
                                 page.get(), thumb_buf.data(), length_bytes));
    EXPECT_EQ(kHashedDecodedData, GenerateMD5Base16(thumb_buf));
  }

  {
    const char kHashedDecodedData[] = "e81123a573378ba1ea80461d25cc41f6";
    const unsigned long kExpectedSize = 1110u;

    ScopedPage page = LoadScopedPage(1);
    ASSERT_TRUE(page);

    unsigned long length_bytes =
        FPDFPage_GetDecodedThumbnailData(page.get(), nullptr, 0);
    ASSERT_EQ(kExpectedSize, length_bytes);
    std::vector<uint8_t> thumb_buf(length_bytes);

    EXPECT_EQ(kExpectedSize, FPDFPage_GetDecodedThumbnailData(
                                 page.get(), thumb_buf.data(), length_bytes));
    EXPECT_EQ(kHashedDecodedData, GenerateMD5Base16(thumb_buf));
  }
}

TEST_F(FPDFThumbnailEmbedderTest,
       GetDecodedThumbnailDataFromPageWithNoFilters) {
  ASSERT_TRUE(OpenDocument("thumbnail_with_no_filters.pdf"));

  const unsigned long kExpectedSize = 301u;

  ScopedPage page = LoadScopedPage(0);
  ASSERT_TRUE(page);

  unsigned long length_bytes =
      FPDFPage_GetDecodedThumbnailData(page.get(), nullptr, 0);
  ASSERT_EQ(kExpectedSize, length_bytes);
  std::vector<uint8_t> thumb_buf(length_bytes);

  EXPECT_EQ(kExpectedSize, FPDFPage_GetDecodedThumbnailData(
                               page.get(), thumb_buf.data(), length_bytes));
  EXPECT_EQ(kThumbnailWithNoFiltersChecksum, GenerateMD5Base16(thumb_buf));
}

TEST_F(FPDFThumbnailEmbedderTest,
       GetDecodedThumbnailDataFromPageWithNoThumbnails) {
  ASSERT_TRUE(OpenDocument("hello_world.pdf"));

  ScopedPage page = LoadScopedPage(0);
  ASSERT_TRUE(page);

  EXPECT_EQ(0u, FPDFPage_GetDecodedThumbnailData(page.get(), nullptr, 0));
}

TEST_F(FPDFThumbnailEmbedderTest, GetDecodedThumbnailDataFromPageNullPage) {
  EXPECT_EQ(0u, FPDFPage_GetDecodedThumbnailData(nullptr, nullptr, 0));
}

TEST_F(FPDFThumbnailEmbedderTest, GetRawThumbnailDataFromPageWithFilters) {
  ASSERT_TRUE(OpenDocument("simple_thumbnail.pdf"));

  {
    const unsigned long kExpectedSize = 1851u;

    ScopedPage page = LoadScopedPage(0);
    ASSERT_TRUE(page);

    unsigned long length_bytes =
        FPDFPage_GetRawThumbnailData(page.get(), nullptr, 0);
    ASSERT_EQ(kExpectedSize, length_bytes);
    std::vector<uint8_t> thumb_buf(length_bytes);

    EXPECT_EQ(kExpectedSize, FPDFPage_GetRawThumbnailData(
                                 page.get(), thumb_buf.data(), length_bytes));
    EXPECT_EQ(kSimpleThumbnailChecksum, GenerateMD5Base16(thumb_buf));
  }

  {
    const char kHashedRawData[] = "c7558a461d5ecfb1d4757218b473afc0";
    const unsigned long kExpectedSize = 1792u;

    ScopedPage page = LoadScopedPage(1);
    ASSERT_TRUE(page);

    unsigned long length_bytes =
        FPDFPage_GetRawThumbnailData(page.get(), nullptr, 0);
    ASSERT_EQ(kExpectedSize, length_bytes);
    std::vector<uint8_t> thumb_buf(length_bytes);

    EXPECT_EQ(kExpectedSize, FPDFPage_GetRawThumbnailData(
                                 page.get(), thumb_buf.data(), length_bytes));
    EXPECT_EQ(kHashedRawData, GenerateMD5Base16(thumb_buf));
  }
}

TEST_F(FPDFThumbnailEmbedderTest, GetRawThumbnailDataFromPageWithNoFilters) {
  ASSERT_TRUE(OpenDocument("thumbnail_with_no_filters.pdf"));

  const unsigned long kExpectedSize = 301u;

  ScopedPage page = LoadScopedPage(0);
  ASSERT_TRUE(page);

  unsigned long length_bytes =
      FPDFPage_GetRawThumbnailData(page.get(), nullptr, 0);
  ASSERT_EQ(kExpectedSize, length_bytes);
  std::vector<uint8_t> thumb_buf(length_bytes);

  EXPECT_EQ(kExpectedSize, FPDFPage_GetRawThumbnailData(
                               page.get(), thumb_buf.data(), length_bytes));
  EXPECT_EQ(kThumbnailWithNoFiltersChecksum, GenerateMD5Base16(thumb_buf));
}

TEST_F(FPDFThumbnailEmbedderTest, GetRawThumbnailDataFromPageWithNoThumbnails) {
  ASSERT_TRUE(OpenDocument("hello_world.pdf"));

  ScopedPage page = LoadScopedPage(0);
  ASSERT_TRUE(page);

  EXPECT_EQ(0u, FPDFPage_GetRawThumbnailData(page.get(), nullptr, 0));
}

TEST_F(FPDFThumbnailEmbedderTest, GetRawThumbnailDataFromPageNullPage) {
  EXPECT_EQ(0u, FPDFPage_GetRawThumbnailData(nullptr, nullptr, 0));
}

TEST_F(FPDFThumbnailEmbedderTest, GetThumbnailAsBitmapFromPage) {
  ASSERT_TRUE(OpenDocument("simple_thumbnail.pdf"));

  {
    ScopedPage page = LoadScopedPage(0);
    ASSERT_TRUE(page);

    ScopedFPDFBitmap thumb_bitmap(FPDFPage_GetThumbnailAsBitmap(page.get()));

    EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(thumb_bitmap.get()));
    CompareBitmap(thumb_bitmap.get(), "simple_thumbnail0");
  }

  {
    ScopedPage page = LoadScopedPage(1);
    ASSERT_TRUE(page);

    ScopedFPDFBitmap thumb_bitmap(FPDFPage_GetThumbnailAsBitmap(page.get()));

    EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(thumb_bitmap.get()));
    CompareBitmap(thumb_bitmap.get(), "simple_thumbnail1");
  }
}

TEST_F(FPDFThumbnailEmbedderTest,
       GetThumbnailAsBitmapFromPageWithoutThumbnail) {
  ASSERT_TRUE(OpenDocument("hello_world.pdf"));

  ScopedPage page = LoadScopedPage(0);
  ASSERT_TRUE(page);

  ScopedFPDFBitmap thumb_bitmap(FPDFPage_GetThumbnailAsBitmap(page.get()));
  ASSERT_EQ(nullptr, thumb_bitmap.get());
}

TEST_F(FPDFThumbnailEmbedderTest,
       GetThumbnailAsBitmapFromThumbnailWithEmptyStream) {
  ASSERT_TRUE(OpenDocument("thumbnail_with_empty_stream.pdf"));

  ScopedPage page = LoadScopedPage(0);
  ASSERT_TRUE(page);

  ScopedFPDFBitmap thumb_bitmap(FPDFPage_GetThumbnailAsBitmap(page.get()));
  ASSERT_EQ(nullptr, thumb_bitmap.get());
}

TEST_F(FPDFThumbnailEmbedderTest,
       GetThumbnailAsBitmapFromThumbnailWithNoFilters) {
  ASSERT_TRUE(OpenDocument("thumbnail_with_no_filters.pdf"));

  ScopedPage page = LoadScopedPage(0);
  ASSERT_TRUE(page);

  ScopedFPDFBitmap thumb_bitmap(FPDFPage_GetThumbnailAsBitmap(page.get()));

  EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(thumb_bitmap.get()));
  CompareBitmap(thumb_bitmap.get(), "thumbnail_with_no_filters");
}

TEST_F(FPDFThumbnailEmbedderTest, GetThumbnailDoesNotAlterPage) {
  ASSERT_TRUE(OpenDocument("simple_thumbnail.pdf"));

  const unsigned long kExpectedRawSize = 1851u;

  ScopedPage page = LoadScopedPage(0);
  ASSERT_TRUE(page);

  // Get the raw data
  unsigned long raw_size = FPDFPage_GetRawThumbnailData(page.get(), nullptr, 0);
  ASSERT_EQ(kExpectedRawSize, raw_size);
  std::vector<uint8_t> raw_thumb_buf(raw_size);

  EXPECT_EQ(kExpectedRawSize, FPDFPage_GetRawThumbnailData(
                                  page.get(), raw_thumb_buf.data(), raw_size));
  EXPECT_EQ(kSimpleThumbnailChecksum, GenerateMD5Base16(raw_thumb_buf));

  // Get the thumbnail
  ScopedFPDFBitmap thumb_bitmap(FPDFPage_GetThumbnailAsBitmap(page.get()));

  EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(thumb_bitmap.get()));
  CompareBitmap(thumb_bitmap.get(), "simple_thumbnail0");

  // Get the raw data again
  unsigned long new_raw_size =
      FPDFPage_GetRawThumbnailData(page.get(), nullptr, 0);
  ASSERT_EQ(kExpectedRawSize, new_raw_size);
  std::vector<uint8_t> new_raw_thumb_buf(new_raw_size);

  EXPECT_EQ(kExpectedRawSize,
            FPDFPage_GetRawThumbnailData(page.get(), new_raw_thumb_buf.data(),
                                         new_raw_size));
  EXPECT_EQ(kSimpleThumbnailChecksum, GenerateMD5Base16(new_raw_thumb_buf));
}

TEST_F(FPDFThumbnailEmbedderTest, GetThumbnailAsBitmapFromPageNullPage) {
  EXPECT_FALSE(FPDFPage_GetThumbnailAsBitmap(nullptr));
}
