chromium/chrome/browser/compose/chrome_compose_client_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/compose/chrome_compose_client.h"

#include <memory>
#include <utility>

#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversion_utils.h"
#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/metrics/user_action_tester.h"
#include "base/test/mock_callback.h"
#include "base/test/protobuf_matchers.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "base/time/time.h"
#include "chrome/browser/compose/compose_enabling.h"
#include "chrome/browser/optimization_guide/mock_optimization_guide_keyed_service.h"
#include "chrome/browser/segmentation_platform/segmentation_platform_service_factory.h"
#include "chrome/common/compose/compose.mojom.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/autofill/content/browser/content_autofill_client.h"
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/content/browser/test_autofill_client_injector.h"
#include "components/autofill/content/browser/test_autofill_manager_injector.h"
#include "components/autofill/content/browser/test_content_autofill_client.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/filling_product.h"
#include "components/autofill/core/browser/test_autofill_manager_waiter.h"
#include "components/autofill/core/browser/test_browser_autofill_manager.h"
#include "components/autofill/core/browser/ui/suggestion.h"
#include "components/autofill/core/browser/ui/suggestion_type.h"
#include "components/autofill/core/common/aliases.h"
#include "components/autofill/core/common/autofill_test_utils.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/unique_ids.h"
#include "components/compose/core/browser/compose_features.h"
#include "components/compose/core/browser/compose_metrics.h"
#include "components/compose/core/browser/config.h"
#include "components/optimization_guide/core/mock_optimization_guide_model_executor.h"
#include "components/optimization_guide/core/model_quality/feature_type_map.h"
#include "components/optimization_guide/core/model_quality/model_quality_log_entry.h"
#include "components/optimization_guide/core/model_quality/test_model_quality_logs_uploader_service.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
#include "components/optimization_guide/core/optimization_guide_model_executor.h"
#include "components/optimization_guide/proto/features/compose.pb.h"
#include "components/optimization_guide/proto/model_execution.pb.h"
#include "components/optimization_guide/proto/model_quality_service.pb.h"
#include "components/segmentation_platform/public/constants.h"
#include "components/segmentation_platform/public/testing/mock_segmentation_platform_service.h"
#include "components/ukm/test_ukm_recorder.h"
#include "components/unified_consent/pref_names.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents_user_data.h"
#include "content/public/test/test_renderer_host.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/network/test/test_network_connection_tracker.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

EqualsProto;
RunOnceCallback;
_;
ComposeCallback;
ModelQualityLogEntry;
OptimizationGuideModelExecutionError;
OptimizationGuideModelExecutionResultStreamingCallback;
OptimizationGuideModelStreamingExecutionResult;
StreamingResponse;
TestModelQualityLogsUploaderService;
LogAiDataRequest;
MockSegmentationPlatformService;

namespace {

const uint64_t kSessionIdHigh =;
const uint64_t kSessionIdLow =;
const segmentation_platform::TrainingRequestId kTrainingRequestId =;
constexpr char kTypeURL[] =;

class MockInnerText : public InnerTextProvider {};

class MockComposeDialog : public compose::mojom::ComposeUntrustedDialog {};

}  // namespace

class ChromeComposeClientTest : public BrowserWithTestWindowTest {};

TEST_F(ChromeComposeClientTest, TestCompose) {}

TEST_F(ChromeComposeClientTest, TestComposeServerAndOnDeviceResponses) {}

TEST_F(ChromeComposeClientTest, TestComposeOnDeviceSessionHistograms) {}

TEST_F(ChromeComposeClientTest, TestComposeEmptySession) {}

TEST_F(ChromeComposeClientTest, TestComposeShowContextMenu) {}

TEST_F(ChromeComposeClientTest, TestComposeShowContextMenuAndDialog) {}

TEST_F(ChromeComposeClientTest, TestProactiveNudgeEngagementIsRecorded) {}

TEST_F(ChromeComposeClientTest,
       TestShouldTriggerProactiveNudgeBlockedBySegmentation) {}

TEST_F(ChromeComposeClientTest, TestShouldTriggerProactiveNudgeDisabledUKM) {}

TEST_F(ChromeComposeClientTest, TestShouldTriggerProactiveNudgeEnabled) {}

TEST_F(ChromeComposeClientTest,
       TestShouldTriggerProactiveNudgePageChecksFailUKM) {}

TEST_F(ChromeComposeClientTest, TestProactiveNudgeMSBBDisabled) {}

TEST_F(ChromeComposeClientTest, TestComposeShouldTriggerSavedStateNudgeUKM) {}

TEST_F(ChromeComposeClientTest, TestComposeWithIncompleteResponsesAnimated) {}

TEST_F(ChromeComposeClientTest, TestComposeNoResultAnimation) {}

TEST_F(ChromeComposeClientTest, TestComposeSessionIgnoresPreviousResponse) {}

TEST_F(ChromeComposeClientTest, TestComposeRequestTimeout) {}

TEST_F(ChromeComposeClientTest, TestComposeParams) {}

TEST_F(ChromeComposeClientTest, TestComposeGenericServerError) {}

TEST_F(ChromeComposeClientTest, TestComposeSetTriggeredFromModifierOnError) {}

// Tests that we return an error if Optimization Guide is unable to parse the
// response. In this case the response will be std::nullopt.
TEST_F(ChromeComposeClientTest, TestComposeNoParsedAny) {}

TEST_F(ChromeComposeClientTest, TestOptimizationGuideDisabled) {}

TEST_F(ChromeComposeClientTest, TestNoModelExecutor) {}

TEST_F(ChromeComposeClientTest, TestRestoreStateAfterRequestResponse) {}

TEST_F(ChromeComposeClientTest, TestRestoreEmptyState) {}

// Tests that a saved WebUI state is properly returned.
TEST_F(ChromeComposeClientTest, TestSaveAndRestoreWebUIState) {}

// Tests that the same saved WebUI state is returned after compose().
TEST_F(ChromeComposeClientTest, TestSaveThenComposeThenRestoreWebUIState) {}

TEST_F(ChromeComposeClientTest, NoStateWorksAtChromeCompose) {}

// Tests that closing after showing the dialog does not crash the browser.
TEST_F(ChromeComposeClientTest, TestCloseUI) {}

// Tests that session level UKM metrics are properly captured after closing the
// dialog.
TEST_F(ChromeComposeClientTest, TestCancelUkmMetrics) {}

// Tests that closing the session at chrome-untrusted://compose does not crash
// the browser, even though there is no dialog shown at that URL.
TEST_F(ChromeComposeClientTest, TestCloseUIAtChromeCompose) {}

// Tests that an unpaired high surrogate resulting from truncation by substr is
// properly removed.
TEST_F(ChromeComposeClientTest, TestOpenDialogWithTruncatedSelectedText) {}

// Tests that opening the dialog with user selected text will return that text
// when the WebUI requests initial state.
TEST_F(ChromeComposeClientTest, TestOpenDialogWithSelectedText) {}

// Tests that opening the dialog with selected text from the proactive nudge
// will send that text to the WebUI dialog.
TEST_F(ChromeComposeClientTest,
       TestOpenDialogWithSelectedTextFromProactiveNudge) {}

// Test that opening the saved state dialog with selected text does not start
// a new session or update the initial selection.
TEST_F(ChromeComposeClientTest, TestSelectedTextWithSavedStateNudge) {}

TEST_F(ChromeComposeClientTest,
       TestMultipleDialogOpensWithChangingSelectedText) {}

// Tests that opening the dialog with selected text clears existing state.
TEST_F(ChromeComposeClientTest, TestClearStateWhenOpenWithSelectedText) {}

TEST_F(ChromeComposeClientTest,
       TestContextMenuNotRecordedAsProactiveInQualityLogs) {}

TEST_F(ChromeComposeClientTest, TestProactiveNudgeRecordedInQualityLogs) {}

// Checks proper propagation of Compose config params.
TEST_F(ChromeComposeClientTest, TestInputParams) {}

// Tests that Undo is not possible when Compose is never called and no response
// is ever received.
TEST_F(ChromeComposeClientTest, TestEmptyUndo) {}

// Tests that Undo is not possible after only one Compose() invocation.
// TODO(b/334007229): incorporate redo testing.
TEST_F(ChromeComposeClientTest, TestUndoUnavailableFirstCompose) {}

// Tests Undo after calling Compose() twice.
TEST_F(ChromeComposeClientTest, TestComposeTwiceThenUpdateWebUIStateThenUndo) {}

// Tests if Undo can be done more than once.
// TODO(b/334007229): incorporate redo testing.
TEST_F(ChromeComposeClientTest, TestUndoStackMultipleUndos) {}

// Tests scenario: Undo returns state A, Compose, then undo again returns to
// state A.
TEST_F(ChromeComposeClientTest, TestUndoComposeThenUndoAgain) {}

// Tests that the corresponding callback is run when AcceptComposeResponse is
// called.
TEST_F(ChromeComposeClientTest, TestAcceptComposeResultCallback) {}

TEST_F(ChromeComposeClientTest, BugReportOpensCorrectURL) {}

TEST_F(ChromeComposeClientTest, LearnMoreLinkOpensCorrectURL) {}

TEST_F(ChromeComposeClientTest, SurveyLinkOpensCorrectURL) {}

// Tests that all ComposeSessions are deleted on page navigation.
TEST_F(ChromeComposeClientTest, ResetClientOnNavigation) {}

// Tests that the dialog close button logs to the correct corresponding
// histograms.
TEST_F(ChromeComposeClientTest, CloseButtonHistogramTest) {}

// Tests that the dialog close button logs to the correct corresponding
// histograms.
TEST_F(ChromeComposeClientTest, ExpiredSessionHistogramTest) {}

TEST_F(ChromeComposeClientTest, ExpiredSessionMSBBHistogramTest) {}

TEST_F(ChromeComposeClientTest, ExpiredSessionFirstRunHistogramTest) {}

TEST_F(ChromeComposeClientTest, ExpiredSessionBlocksSavedStateNudgeTest) {}

TEST_F(ChromeComposeClientTest, CloseButtonMSBBHistogramTest) {}

TEST_F(ChromeComposeClientTest,
       CloseButtonMSBBEnabledDuringSessionHistogramTest) {}

TEST_F(ChromeComposeClientTest, FirstRunCloseDialogHistogramTest) {}

TEST_F(ChromeComposeClientTest, FirstRunThenMSBBCloseDialogHistogramTest) {}

TEST_F(ChromeComposeClientTest, MSBBCloseDialogHistogramTest) {}

TEST_F(ChromeComposeClientTest, FirstRunCompletedHistogramTest) {}

TEST_F(ChromeComposeClientTest,
       FirstRunCompletedThenSuggestionAcceptedHistogramTest) {}

TEST_F(ChromeComposeClientTest, CompleteFirstRunTest) {}

TEST_F(ChromeComposeClientTest,
       AddSiteToNeverPromptListBlocksProactiveNudgeTest) {}

TEST_F(ChromeComposeClientTest, TextFieldChangeThresholdHidesProactiveNudge) {}

TEST_F(ChromeComposeClientTest, AcceptSuggestionHistogramTest) {}

TEST_F(ChromeComposeClientTest, LoseFocusHistogramTest) {}

TEST_F(ChromeComposeClientTest, LoseFocusFirstRunHistogramTest) {}

TEST_F(ChromeComposeClientTest, ComposeDialogStatesSeenUserActionsTest) {}

TEST_F(ChromeComposeClientTest, TestAutoCompose) {}

TEST_F(ChromeComposeClientTest, TestAutoComposeTooLong) {}

TEST_F(ChromeComposeClientTest, TestAutoComposeTooFewWords) {}

TEST_F(ChromeComposeClientTest, TestAutoComposeTooManyWords) {}

TEST_F(ChromeComposeClientTest, TestAutoComposeDisabled) {}

TEST_F(ChromeComposeClientTest, TestNoAutoComposeWithPopup) {}

TEST_F(ChromeComposeClientTest, TestAutoComposeWithRepeatedRightClick) {}

TEST_F(ChromeComposeClientTest, TestNoAutoComposeBeforeFirstRun) {}

// Tests that quality logs are uploaded when a new valid response clears forward
// state and when the session is destroyed, and that those logs have the
// expected session IDs attached.
TEST_F(ChromeComposeClientTest, TestComposeQualitySessionId) {}

TEST_F(ChromeComposeClientTest, TestComposeQualityLoggedOnSubsequentError) {}

// Tests that quality logs are uploaded when a new valid response clears forward
// state and when the session is destroyed, and that those logs have expected
// latency data attached.
TEST_F(ChromeComposeClientTest, TestComposeQualityLatency) {}

TEST_F(ChromeComposeClientTest,
       TestComposeQualityOnlyOneLogEntryAbandonedOnClose) {}

TEST_F(ChromeComposeClientTest, TestComposeQualityNewSessionWithSelectedText) {}

TEST_F(ChromeComposeClientTest, TestComposeQualityFinishedWithoutInsert) {}

TEST_F(ChromeComposeClientTest, TestComposeQualityFeedbackPositive) {}

TEST_F(ChromeComposeClientTest, TestComposeQualityFeedbackNegative) {}

TEST_F(ChromeComposeClientTest, TestComposeQualityWasEdited) {}

TEST_F(ChromeComposeClientTest, TestRegenerate) {}

TEST_F(ChromeComposeClientTest, TestToneChange) {}

TEST_F(ChromeComposeClientTest, TestLengthChange) {}

TEST_F(ChromeComposeClientTest, TestOfflineError) {}

TEST_F(ChromeComposeClientTest, TestInnerText) {}

TEST_F(ChromeComposeClientTest, TestInnerTextNodeOffsetNotFound) {}

TEST_F(ChromeComposeClientTest, TestCloseReasonCanceledWhileWaiting) {}

TEST_F(ChromeComposeClientTest, TestShowNudgeAtCursorFeatureFlag) {}

#if defined(GTEST_HAS_DEATH_TEST)
// Tests that the Compose client crashes the browser if a webcontents
// tries to bind mojo without opening the dialog at a non Compose URL.
TEST_F(ChromeComposeClientTest, NoStateCrashesAtOtherUrls) {}

// Tests that the Compose client crashes the browser if a webcontents
// sends any message when the dialog has not been shown.
TEST_F(ChromeComposeClientTest, TestCannotSendMessagesToNotShownDialog) {}

// Tests that the Compose client crashes the browser if a webcontents
// tries to close the dialog when the dialog has not been shown.
TEST_F(ChromeComposeClientTest, TestCannotCloseNotShownDialog) {}

// Tests that the Compose client crashes the browser if a webcontents
// tries to close the dialog when the dialog has not been shown.
TEST_F(ChromeComposeClientTest, TestCannotSendMessagesAfterClosingDialog) {}

// Tests that the Compose client crashes the browser if a webcontents
// sends any more messages after closing the dialog at
// chrome-untrusted://compose.
TEST_F(ChromeComposeClientTest,
       TestCannotSendMessagesAfterClosingDialogAtChromeCompose) {}
#endif  // GTEST_HAS_DEATH_TEST

class ComposePopupAutofillDriverTest : public ChromeComposeClientTest {};

TEST_F(ComposePopupAutofillDriverTest, TestSelectionNudgeNoProactiveNudge) {}

TEST_F(ComposePopupAutofillDriverTest, TestSelectionNudgeEnabled) {}

TEST_F(ComposePopupAutofillDriverTest, TestSelectionTooShort) {}

TEST_F(ComposePopupAutofillDriverTest, TestSelectionNudgeLostFocus) {}

TEST_F(ComposePopupAutofillDriverTest,
       TestSelectionNudgeBlockedBySegmentation) {}

TEST_F(ComposePopupAutofillDriverTest, TestCaretMovementExtendsNudgeDelay) {}

TEST_F(ComposePopupAutofillDriverTest, TestSelectionNudgeNoDelay) {}

TEST_F(ComposePopupAutofillDriverTest, TestSelectionNudgeDisabled) {}

TEST_F(ComposePopupAutofillDriverTest, TestSelectionNudgeOncePerFocus) {}

TEST_F(ComposePopupAutofillDriverTest,
       TestFocusNudgeExtendedToTextChangeNudge) {}

TEST_F(ComposePopupAutofillDriverTest,
       TestFocusNudgeDisabledTextChangeNudgeEnabled) {}