chromium/ash/components/arc/pay/arc_payment_app_bridge_unittest.cc

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

#include "ash/components/arc/pay/arc_payment_app_bridge.h"

#include <optional>
#include <utility>

#include "ash/components/arc/session/arc_bridge_service.h"
#include "ash/components/arc/session/arc_service_manager.h"
#include "ash/components/arc/test/arc_payment_app_bridge_test_support.h"
#include "chromeos/components/payments/mojom/payment_app_types.mojom.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace arc {
namespace {

class ArcPaymentAppBridgeTest : public testing::Test {
 public:
  ArcPaymentAppBridgeTest() = default;
  ~ArcPaymentAppBridgeTest() override = default;

  ArcPaymentAppBridgeTest(const ArcPaymentAppBridgeTest& other) = delete;
  ArcPaymentAppBridgeTest& operator=(const ArcPaymentAppBridgeTest& other) =
      delete;

  void OnPaymentImplementedResponse(
      chromeos::payments::mojom::IsPaymentImplementedResultPtr response) {
    is_implemented_ = std::move(response);
  }

  void OnIsReadyToPayResponse(
      chromeos::payments::mojom::IsReadyToPayResultPtr response) {
    is_ready_to_pay_ = std::move(response);
  }

  void OnInvokePaymentAppResponse(
      chromeos::payments::mojom::InvokePaymentAppResultPtr response) {
    invoke_app_ = std::move(response);
  }

  void OnAbortPaymentAppResponse(bool response) { abort_app_ = response; }

  ArcPaymentAppBridgeTestSupport support_;
  chromeos::payments::mojom::IsPaymentImplementedResultPtr is_implemented_;
  chromeos::payments::mojom::IsReadyToPayResultPtr is_ready_to_pay_;
  chromeos::payments::mojom::InvokePaymentAppResultPtr invoke_app_;
  std::optional<bool> abort_app_;
};

TEST_F(ArcPaymentAppBridgeTest, UnableToConnectInIsImplemented) {
  // Intentionally do not set an instance.

  EXPECT_CALL(*support_.instance(),
              IsPaymentImplemented(testing::_, testing::_))
      .Times(0);

  ArcPaymentAppBridge::GetForBrowserContextForTesting(support_.context())
      ->IsPaymentImplemented(
          "com.example.app",
          base::BindOnce(&ArcPaymentAppBridgeTest::OnPaymentImplementedResponse,
                         base::Unretained(this)));

  ASSERT_FALSE(is_implemented_.is_null());
  EXPECT_FALSE(is_implemented_->is_valid());
  ASSERT_TRUE(is_implemented_->is_error());
  EXPECT_EQ("Unable to invoke Android apps.", is_implemented_->get_error());
}

TEST_F(ArcPaymentAppBridgeTest, IsImplemented) {
  auto scoped_set_instance = support_.CreateScopedSetInstance();

  EXPECT_CALL(*support_.instance(),
              IsPaymentImplemented(testing::_, testing::_))
      .WillOnce(testing::Invoke([](const std::string& package_name,
                                   ArcPaymentAppBridge::
                                       IsPaymentImplementedCallback callback) {
        auto valid =
            chromeos::payments::mojom::IsPaymentImplementedValidResult::New();
        valid->activity_names.push_back("com.example.Activity");
        valid->service_names.push_back("com.example.Service");
        std::move(callback).Run(
            chromeos::payments::mojom::IsPaymentImplementedResult::NewValid(
                std::move(valid)));
      }));

  ArcPaymentAppBridge::GetForBrowserContextForTesting(support_.context())
      ->IsPaymentImplemented(
          "com.example.app",
          base::BindOnce(&ArcPaymentAppBridgeTest::OnPaymentImplementedResponse,
                         base::Unretained(this)));

  ASSERT_FALSE(is_implemented_.is_null());
  EXPECT_FALSE(is_implemented_->is_error());
  ASSERT_TRUE(is_implemented_->is_valid());
  ASSERT_FALSE(is_implemented_->get_valid().is_null());
  EXPECT_EQ(std::vector<std::string>{"com.example.Activity"},
            is_implemented_->get_valid()->activity_names);
  EXPECT_EQ(std::vector<std::string>{"com.example.Service"},
            is_implemented_->get_valid()->service_names);
}

TEST_F(ArcPaymentAppBridgeTest, IsNotImplemented) {
  auto scoped_set_instance = support_.CreateScopedSetInstance();

  EXPECT_CALL(*support_.instance(),
              IsPaymentImplemented(testing::_, testing::_))
      .WillOnce(testing::Invoke(
          [](const std::string& package_name,
             ArcPaymentAppBridge::IsPaymentImplementedCallback callback) {
            std::move(callback).Run(
                chromeos::payments::mojom::IsPaymentImplementedResult::NewValid(
                    chromeos::payments::mojom::IsPaymentImplementedValidResult::
                        New()));
          }));

  ArcPaymentAppBridge::GetForBrowserContextForTesting(support_.context())
      ->IsPaymentImplemented(
          "com.example.app",
          base::BindOnce(&ArcPaymentAppBridgeTest::OnPaymentImplementedResponse,
                         base::Unretained(this)));

  ASSERT_FALSE(is_implemented_.is_null());
  EXPECT_FALSE(is_implemented_->is_error());
  ASSERT_TRUE(is_implemented_->is_valid());
  ASSERT_FALSE(is_implemented_->get_valid().is_null());
  EXPECT_TRUE(is_implemented_->get_valid()->activity_names.empty());
  EXPECT_TRUE(is_implemented_->get_valid()->service_names.empty());
}

TEST_F(ArcPaymentAppBridgeTest, ImplementationCheckError) {
  auto scoped_set_instance = support_.CreateScopedSetInstance();

  EXPECT_CALL(*support_.instance(),
              IsPaymentImplemented(testing::_, testing::_))
      .WillOnce(testing::Invoke(
          [](const std::string& package_name,
             ArcPaymentAppBridge::IsPaymentImplementedCallback callback) {
            std::move(callback).Run(
                chromeos::payments::mojom::IsPaymentImplementedResult::NewError(
                    "Error message."));
          }));

  ArcPaymentAppBridge::GetForBrowserContextForTesting(support_.context())
      ->IsPaymentImplemented(
          "com.example.app",
          base::BindOnce(&ArcPaymentAppBridgeTest::OnPaymentImplementedResponse,
                         base::Unretained(this)));

  ASSERT_FALSE(is_implemented_.is_null());
  EXPECT_FALSE(is_implemented_->is_valid());
  ASSERT_TRUE(is_implemented_->is_error());
  EXPECT_EQ("Error message.", is_implemented_->get_error());
}

TEST_F(ArcPaymentAppBridgeTest, UnableToConnectInIsReadyToPay) {
  // Intentionally do not set an instance.

  EXPECT_CALL(*support_.instance(), IsReadyToPay(testing::_, testing::_))
      .Times(0);

  ArcPaymentAppBridge::GetForBrowserContextForTesting(support_.context())
      ->IsReadyToPay(
          chromeos::payments::mojom::PaymentParameters::New(),
          base::BindOnce(&ArcPaymentAppBridgeTest::OnIsReadyToPayResponse,
                         base::Unretained(this)));

  ASSERT_FALSE(is_ready_to_pay_.is_null());
  EXPECT_FALSE(is_ready_to_pay_->is_response());
  ASSERT_TRUE(is_ready_to_pay_->is_error());
  EXPECT_EQ("Unable to invoke Android apps.", is_ready_to_pay_->get_error());
}

TEST_F(ArcPaymentAppBridgeTest, IsReadyToPay) {
  auto scoped_set_instance = support_.CreateScopedSetInstance();

  EXPECT_CALL(*support_.instance(), IsReadyToPay(testing::_, testing::_))
      .WillOnce(testing::Invoke(
          [](chromeos::payments::mojom::PaymentParametersPtr parameters,
             ArcPaymentAppBridge::IsReadyToPayCallback callback) {
            std::move(callback).Run(
                chromeos::payments::mojom::IsReadyToPayResult::NewResponse(
                    true));
          }));

  ArcPaymentAppBridge::GetForBrowserContextForTesting(support_.context())
      ->IsReadyToPay(
          chromeos::payments::mojom::PaymentParameters::New(),
          base::BindOnce(&ArcPaymentAppBridgeTest::OnIsReadyToPayResponse,
                         base::Unretained(this)));

  ASSERT_FALSE(is_ready_to_pay_.is_null());
  EXPECT_FALSE(is_ready_to_pay_->is_error());
  ASSERT_TRUE(is_ready_to_pay_->is_response());
  EXPECT_TRUE(is_ready_to_pay_->get_response());
}

TEST_F(ArcPaymentAppBridgeTest, IsNotReadyToPay) {
  auto scoped_set_instance = support_.CreateScopedSetInstance();

  EXPECT_CALL(*support_.instance(), IsReadyToPay(testing::_, testing::_))
      .WillOnce(testing::Invoke(
          [](chromeos::payments::mojom::PaymentParametersPtr parameters,
             ArcPaymentAppBridge::IsReadyToPayCallback callback) {
            std::move(callback).Run(
                chromeos::payments::mojom::IsReadyToPayResult::NewResponse(
                    false));
          }));

  ArcPaymentAppBridge::GetForBrowserContextForTesting(support_.context())
      ->IsReadyToPay(
          chromeos::payments::mojom::PaymentParameters::New(),
          base::BindOnce(&ArcPaymentAppBridgeTest::OnIsReadyToPayResponse,
                         base::Unretained(this)));

  ASSERT_FALSE(is_ready_to_pay_.is_null());
  EXPECT_FALSE(is_ready_to_pay_->is_error());
  ASSERT_TRUE(is_ready_to_pay_->is_response());
  EXPECT_FALSE(is_ready_to_pay_->get_response());
}

TEST_F(ArcPaymentAppBridgeTest, UnableToConnectInInvokePaymentApp) {
  // Intentionally do not set an instance.

  EXPECT_CALL(*support_.instance(), InvokePaymentApp(testing::_, testing::_))
      .Times(0);

  ArcPaymentAppBridge::GetForBrowserContextForTesting(support_.context())
      ->InvokePaymentApp(
          chromeos::payments::mojom::PaymentParameters::New(),
          base::BindOnce(&ArcPaymentAppBridgeTest::OnInvokePaymentAppResponse,
                         base::Unretained(this)));

  ASSERT_FALSE(invoke_app_.is_null());
  EXPECT_FALSE(invoke_app_->is_valid());
  ASSERT_TRUE(invoke_app_->is_error());
  EXPECT_EQ("Unable to invoke Android apps.", invoke_app_->get_error());
}

TEST_F(ArcPaymentAppBridgeTest, InvokePaymentAppResultOK) {
  auto scoped_set_instance = support_.CreateScopedSetInstance();

  EXPECT_CALL(*support_.instance(), InvokePaymentApp(testing::_, testing::_))
      .WillOnce(testing::Invoke(
          [](chromeos::payments::mojom::PaymentParametersPtr parameters,
             ArcPaymentAppBridge::InvokePaymentAppCallback callback) {
            auto valid =
                chromeos::payments::mojom::InvokePaymentAppValidResult::New();
            valid->is_activity_result_ok = true;
            valid->stringified_details = "{}";
            std::move(callback).Run(
                chromeos::payments::mojom::InvokePaymentAppResult::NewValid(
                    std::move(valid)));
          }));

  ArcPaymentAppBridge::GetForBrowserContextForTesting(support_.context())
      ->InvokePaymentApp(
          chromeos::payments::mojom::PaymentParameters::New(),
          base::BindOnce(&ArcPaymentAppBridgeTest::OnInvokePaymentAppResponse,
                         base::Unretained(this)));

  ASSERT_FALSE(invoke_app_.is_null());
  EXPECT_FALSE(invoke_app_->is_error());
  ASSERT_TRUE(invoke_app_->is_valid());
  ASSERT_FALSE(invoke_app_->get_valid().is_null());
  EXPECT_TRUE(invoke_app_->get_valid()->is_activity_result_ok);
  EXPECT_EQ("{}", invoke_app_->get_valid()->stringified_details);
}

TEST_F(ArcPaymentAppBridgeTest, InvokePaymentAppResultCancelled) {
  auto scoped_set_instance = support_.CreateScopedSetInstance();

  EXPECT_CALL(*support_.instance(), InvokePaymentApp(testing::_, testing::_))
      .WillOnce(testing::Invoke(
          [](chromeos::payments::mojom::PaymentParametersPtr parameters,
             ArcPaymentAppBridge::InvokePaymentAppCallback callback) {
            auto valid =
                chromeos::payments::mojom::InvokePaymentAppValidResult::New();
            // User cancelled payment.
            valid->is_activity_result_ok = false;
            std::move(callback).Run(
                chromeos::payments::mojom::InvokePaymentAppResult::NewValid(
                    std::move(valid)));
          }));

  ArcPaymentAppBridge::GetForBrowserContextForTesting(support_.context())
      ->InvokePaymentApp(
          chromeos::payments::mojom::PaymentParameters::New(),
          base::BindOnce(&ArcPaymentAppBridgeTest::OnInvokePaymentAppResponse,
                         base::Unretained(this)));

  ASSERT_FALSE(invoke_app_.is_null());
  EXPECT_FALSE(invoke_app_->is_error());
  ASSERT_TRUE(invoke_app_->is_valid());
  ASSERT_FALSE(invoke_app_->get_valid().is_null());
  EXPECT_FALSE(invoke_app_->get_valid()->is_activity_result_ok);
}

TEST_F(ArcPaymentAppBridgeTest, InvokePaymentAppError) {
  auto scoped_set_instance = support_.CreateScopedSetInstance();

  EXPECT_CALL(*support_.instance(), InvokePaymentApp(testing::_, testing::_))
      .WillOnce(testing::Invoke(
          [](chromeos::payments::mojom::PaymentParametersPtr parameters,
             ArcPaymentAppBridge::InvokePaymentAppCallback callback) {
            std::move(callback).Run(
                chromeos::payments::mojom::InvokePaymentAppResult::NewError(
                    "Error message."));
          }));

  ArcPaymentAppBridge::GetForBrowserContextForTesting(support_.context())
      ->InvokePaymentApp(
          chromeos::payments::mojom::PaymentParameters::New(),
          base::BindOnce(&ArcPaymentAppBridgeTest::OnInvokePaymentAppResponse,
                         base::Unretained(this)));

  ASSERT_FALSE(invoke_app_.is_null());
  EXPECT_FALSE(invoke_app_->is_valid());
  ASSERT_TRUE(invoke_app_->is_error());
  EXPECT_EQ("Error message.", invoke_app_->get_error());
}

TEST_F(ArcPaymentAppBridgeTest, UnableToConnectAbortPaymentApp) {
  // Intentionally do not set an instance.

  EXPECT_CALL(*support_.instance(), AbortPaymentApp(testing::_, testing::_))
      .Times(0);

  ArcPaymentAppBridge::GetForBrowserContextForTesting(support_.context())
      ->AbortPaymentApp(
          "some token",
          base::BindOnce(&ArcPaymentAppBridgeTest::OnAbortPaymentAppResponse,
                         base::Unretained(this)));

  ASSERT_TRUE(abort_app_.has_value());
  ASSERT_FALSE(abort_app_.value());
}

TEST_F(ArcPaymentAppBridgeTest, AbortPaymentAppOK) {
  auto scoped_set_instance = support_.CreateScopedSetInstance();

  EXPECT_CALL(*support_.instance(), AbortPaymentApp(testing::_, testing::_))
      .WillOnce(testing::Invoke(
          [](const std::string& request_token,
             ArcPaymentAppBridge::AbortPaymentAppCallback callback) {
            std::move(callback).Run(true);
          }));

  ArcPaymentAppBridge::GetForBrowserContextForTesting(support_.context())
      ->AbortPaymentApp(
          "some token",
          base::BindOnce(&ArcPaymentAppBridgeTest::OnAbortPaymentAppResponse,
                         base::Unretained(this)));

  ASSERT_TRUE(abort_app_.has_value());
  ASSERT_TRUE(abort_app_.value());
}

}  // namespace
}  // namespace arc