chromium/chrome/browser/ui/android/hats/survey_client_android_unittest.cc

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

#include "chrome/browser/ui/android/hats/survey_client_android.h"

#include <memory>

#include "base/android/callback_android.h"
#include "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/android/hats/survey_ui_delegate_android.h"
#include "chrome/browser/ui/android/hats/test/test_survey_utils_bridge.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/android/window_android.h"

using base::android::ScopedJavaGlobalRef;

namespace hats {
namespace {
const char kTestSurveyTrigger[] = "testing";
const SurveyBitsData kTestSurveyProductSpecificBitsData{
    {"Test Field 1", true},
    {"Test Field 2", false}};
const SurveyStringData kTestSurveyProductSpecificStringData{
    {"Test Field 3", "Test value"}};
}  // namespace

// Custom implementation resenting a C++ implemented SurveyUiDelegate.
class TestSurveyUiDelegate : public SurveyUiDelegateAndroid {
 public:
  explicit TestSurveyUiDelegate(JNIEnv* env) : env_(env) {}

  ~TestSurveyUiDelegate() override = default;

  void AcceptSurvey() {
    DCHECK(on_accepted_callback_);
    base::android::RunRunnableAndroid(on_accepted_callback_);
  }

  void DeclineSurvey() {
    DCHECK(on_declined_callback_);
    base::android::RunRunnableAndroid(on_declined_callback_);
  }

  void ShowSurveyInvitation(
      JNIEnv* env,
      const JavaParamRef<jobject>& on_accepted_callback,
      const JavaParamRef<jobject>& on_declined_callback,
      const JavaParamRef<jobject>& on_presentation_failed_callback) override {
    on_accepted_callback_ = on_accepted_callback;
    on_declined_callback_ = on_declined_callback;
    on_presentation_failed_callback_ = on_presentation_failed_callback;
  }

  // Dismiss the survey invitation.
  void Dismiss(JNIEnv* env) override {}

 private:
  raw_ptr<JNIEnv> env_;
  ScopedJavaGlobalRef<jobject> on_accepted_callback_;
  ScopedJavaGlobalRef<jobject> on_declined_callback_;
  ScopedJavaGlobalRef<jobject> on_presentation_failed_callback_;
};

class SurveyClientAndroidTest : public testing::Test {
 public:
  SurveyClientAndroidTest(const SurveyClientAndroidTest&) = delete;
  SurveyClientAndroidTest& operator=(const SurveyClientAndroidTest&) = delete;

 protected:
  content::BrowserTaskEnvironment task_environment_{
      base::test::TaskEnvironment::TimeSource::MOCK_TIME};

  SurveyClientAndroidTest() = default;

  void SetUp() override {
    testing::Test::SetUp();
    profile_manager_ = std::make_unique<TestingProfileManager>(
        TestingBrowserProcess::GetGlobal());
    ASSERT_TRUE(profile_manager_->SetUp());
    profile_ = profile_manager_->CreateTestingProfile("test_profile");
    TestSurveyUtilsBridge::SetUpJavaTestSurveyFactory();
  }

  std::unique_ptr<SurveyClientAndroid> survey_client_;
  std::unique_ptr<TestingProfileManager> profile_manager_;
  raw_ptr<TestingProfile> profile_;
};

TEST_F(SurveyClientAndroidTest, CreateSurveyClientWithStaticTriggerId) {
  std::unique_ptr<ui::WindowAndroid::ScopedWindowAndroidForTesting> window =
      ui::WindowAndroid::CreateForTesting();
  JNIEnv* env = base::android::AttachCurrentThread();
  std::unique_ptr<TestSurveyUiDelegate> delegate =
      std::make_unique<TestSurveyUiDelegate>(env);
  survey_client_ = std::make_unique<SurveyClientAndroid>(
      kTestSurveyTrigger, delegate.get(), profile_,
      /*supplied_trigger_id=*/std::nullopt);

  survey_client_->LaunchSurvey(window->get(),
                               kTestSurveyProductSpecificBitsData,
                               kTestSurveyProductSpecificStringData);

  delegate->AcceptSurvey();

  std::string last_shown_trigger =
      TestSurveyUtilsBridge::GetLastShownSurveyTriggerId();
  ASSERT_FALSE(last_shown_trigger.empty());
  ASSERT_EQ(last_shown_trigger, kHatsNextSurveyTriggerIDTesting);
}

TEST_F(SurveyClientAndroidTest, CreateSurveyClientWithDynamicTriggerId) {
  std::unique_ptr<ui::WindowAndroid::ScopedWindowAndroidForTesting> window =
      ui::WindowAndroid::CreateForTesting();
  JNIEnv* env = base::android::AttachCurrentThread();
  std::unique_ptr<TestSurveyUiDelegate> delegate =
      std::make_unique<TestSurveyUiDelegate>(env);

  const std::string kSuppliedTriggerId = "SomeOtherId";
  survey_client_ = std::make_unique<SurveyClientAndroid>(
      kTestSurveyTrigger, delegate.get(), profile_,
      /*supplied_trigger_id=*/kSuppliedTriggerId);

  survey_client_->LaunchSurvey(window->get(),
                               kTestSurveyProductSpecificBitsData,
                               kTestSurveyProductSpecificStringData);

  delegate->AcceptSurvey();

  std::string last_shown_trigger =
      TestSurveyUtilsBridge::GetLastShownSurveyTriggerId();
  ASSERT_FALSE(last_shown_trigger.empty());
  ASSERT_EQ(last_shown_trigger, kSuppliedTriggerId);
}

}  // namespace hats