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

#include "core/fpdfdoc/cpdf_interactiveform.h"

#include <memory>

#include "constants/catalog.h"
#include "core/fpdfapi/page/test_with_page_module.h"
#include "core/fpdfapi/parser/cpdf_array.h"
#include "core/fpdfapi/parser/cpdf_dictionary.h"
#include "core/fpdfapi/parser/cpdf_name.h"
#include "core/fpdfapi/parser/cpdf_reference.h"
#include "core/fpdfapi/parser/cpdf_stream.h"
#include "core/fpdfapi/parser/cpdf_string.h"
#include "core/fpdfapi/parser/cpdf_test_document.h"
#include "core/fxcrt/string_view_template.h"
#include "testing/gtest/include/gtest/gtest.h"

using CPDFInteractiveFormTest = TestWithPageModule;

TEST_F(CPDFInteractiveFormTest, LoadFieldsWithReferencedNames) {
  auto doc = std::make_unique<CPDF_TestDocument>();
  doc->CreateNewDoc();
  RetainPtr<CPDF_Dictionary> root = doc->GetMutableRoot();
  ASSERT_TRUE(root);

  // For use in the field dictionaries below in the /T field. The field type
  // should be string.
  auto good_string = doc->NewIndirect<CPDF_String>("good_string");
  auto bad_name = doc->NewIndirect<CPDF_Name>("bad_name");

  auto bad_stream = doc->NewIndirect<CPDF_Stream>(doc->New<CPDF_Dictionary>());
  bad_stream->SetData(ByteStringView("bad_stream").unsigned_span());

  auto acroform_dict =
      root->SetNewFor<CPDF_Dictionary>(pdfium::catalog::kAcroForm);
  auto fields_array = acroform_dict->SetNewFor<CPDF_Array>("Fields");

  auto good_string_field_dict = fields_array->AppendNew<CPDF_Dictionary>();
  good_string_field_dict->SetNewFor<CPDF_Name>("Type", "Annot");
  good_string_field_dict->SetNewFor<CPDF_Name>("Subtype", "Widget");
  good_string_field_dict->SetNewFor<CPDF_Name>("FT", "Btn");
  good_string_field_dict->SetNewFor<CPDF_Reference>("T", doc.get(),
                                                    good_string->GetObjNum());

  auto bad_name_field_dict = fields_array->AppendNew<CPDF_Dictionary>();
  bad_name_field_dict->SetNewFor<CPDF_Name>("Type", "Annot");
  bad_name_field_dict->SetNewFor<CPDF_Name>("Subtype", "Widget");
  bad_name_field_dict->SetNewFor<CPDF_Name>("FT", "Btn");
  bad_name_field_dict->SetNewFor<CPDF_Reference>("T", doc.get(),
                                                 bad_name->GetObjNum());

  auto bad_stream_field_dict = fields_array->AppendNew<CPDF_Dictionary>();
  bad_stream_field_dict->SetNewFor<CPDF_Name>("Type", "Annot");
  bad_stream_field_dict->SetNewFor<CPDF_Name>("Subtype", "Widget");
  bad_stream_field_dict->SetNewFor<CPDF_Name>("FT", "Btn");
  bad_stream_field_dict->SetNewFor<CPDF_Reference>("T", doc.get(),
                                                   bad_stream->GetObjNum());

  // Let `interactive_form` parse the dictionaries above and fix them up.
  CPDF_InteractiveForm interactive_form(doc.get());

  auto good_string_field_t = good_string_field_dict->GetStringFor("T");
  ASSERT_TRUE(good_string_field_t);
  EXPECT_EQ("good_string", good_string_field_t->GetString());

  auto bad_name_field_t = bad_name_field_dict->GetStringFor("T");
  ASSERT_TRUE(bad_name_field_t);
  EXPECT_TRUE(bad_name_field_t->GetString().IsEmpty());

  auto bad_stream_field_t = bad_stream_field_dict->GetStringFor("T");
  ASSERT_TRUE(bad_stream_field_t);
  EXPECT_TRUE(bad_stream_field_t->GetString().IsEmpty());
}
