chromium/ios/chrome/browser/ui/price_notifications/cells/price_notifications_table_view_item_unittest.mm

// 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.

#import "ios/chrome/browser/ui/price_notifications/cells/price_notifications_table_view_item.h"

#import <UIKit/UIKit.h>

#import "ios/chrome/browser/shared/ui/table_view/legacy_chrome_table_view_styler.h"
#import "ios/chrome/browser/ui/price_notifications/cells/price_notifications_price_chip_view.h"
#import "ios/chrome/browser/ui/price_notifications/cells/price_notifications_track_button_util.h"
#import "ios/chrome/common/ui/colors/semantic_color_names.h"
#import "testing/gtest_mac.h"
#import "testing/platform_test.h"
#import "url/gurl.h"

using PriceNotificationsTableViewItemTest = PlatformTest;
// Ensures that the PriceNotificationTableViewCell's track button is visible
// while the menu button is hidden if the cell contains a trackable product.
TEST_F(PriceNotificationsTableViewItemTest,
       EnsuresTrackButtonIsDisplayedForTrackableItems) {
  PriceNotificationsTableViewCell* cell =
      [[PriceNotificationsTableViewCell alloc]
            initWithStyle:UITableViewCellStyleDefault
          reuseIdentifier:nil];

  cell.tracking = NO;

  EXPECT_EQ(cell.trackButton.hidden, NO);
  EXPECT_EQ(cell.menuButton.hidden, YES);
}

// Ensures that the PriceNotificationTableViewCell's track button is hidden
// while the menu button is visible if the cell contains a tracked product.
TEST_F(PriceNotificationsTableViewItemTest,
       EnsuresTrackButtonIsNotDisplayedForTrackedItems) {
  PriceNotificationsTableViewCell* cell =
      [[PriceNotificationsTableViewCell alloc]
            initWithStyle:UITableViewCellStyleDefault
          reuseIdentifier:nil];

  cell.tracking = YES;

  EXPECT_EQ(cell.trackButton.hidden, YES);
  EXPECT_EQ(cell.menuButton.hidden, NO);
}

// Ensures that the PriceNotificationTableViewCell's
// PriceNotificationsPriceChipView's background color is gray if only one price
// is given.
TEST_F(PriceNotificationsTableViewItemTest,
       PriceChipViewBackgroundColorIsGrayWithOnePrice) {
  PriceNotificationsTableViewCell* cell =
      [[PriceNotificationsTableViewCell alloc]
            initWithStyle:UITableViewCellStyleDefault
          reuseIdentifier:nil];

  [cell.priceNotificationsChip setPriceDrop:nil previousPrice:@"$10"];

  EXPECT_EQ([cell.priceNotificationsChip.backgroundColor
                isEqual:[UIColor colorNamed:kGrey100Color]],
            true);
}

// Ensures that the PriceNotificationTableViewCell's
// PriceNotificationsPriceChipView's background color is green if only two
// prices are given.
TEST_F(PriceNotificationsTableViewItemTest,
       PriceChipViewBackgroundColorIsGreenWithPriceDrop) {
  PriceNotificationsTableViewCell* cell =
      [[PriceNotificationsTableViewCell alloc]
            initWithStyle:UITableViewCellStyleDefault
          reuseIdentifier:nil];

  [cell.priceNotificationsChip setPriceDrop:@"$5" previousPrice:@"$10"];

  EXPECT_EQ([cell.priceNotificationsChip.backgroundColor
                isEqual:[UIColor colorNamed:kGreen100Color]],
            true);
}

// Ensures that the PriceNotificationsTableViewCell's Menu Button can be tapped
// if the users taps anywhere within a 44pt x 44pt area around the menu button.
TEST_F(PriceNotificationsTableViewItemTest,
       MenuButtonIsTappedWithPointsWithinBoundary) {
  PriceNotificationsTableViewCell* cell =
      [[PriceNotificationsTableViewCell alloc]
            initWithStyle:UITableViewCellStyleDefault
          reuseIdentifier:nil];
  CGPoint valid_points[] = {CGPointMake(0, 0),    CGPointMake(10, 5),
                            CGPointMake(20, -10), CGPointMake(23, 0),
                            CGPointMake(-23, 0),  CGPointMake(0, 23),
                            CGPointMake(0, -23),  CGPointMake(23, -23)};

  for (CGPoint point : valid_points) {
    EXPECT_TRUE([cell.menuButton pointInside:point withEvent:nil]);
  }
}

// Ensures that the PriceNotificationsTableViewCell's Menu Button is not
// activated if the users taps anywhere outside of a 44pt x 44pt area around the
// menu button.
TEST_F(PriceNotificationsTableViewItemTest,
       MenuButtonIsTappedWithPointsOutsideBoundary) {
  PriceNotificationsTableViewCell* cell =
      [[PriceNotificationsTableViewCell alloc]
            initWithStyle:UITableViewCellStyleDefault
          reuseIdentifier:nil];
  CGPoint valid_points[] = {CGPointMake(24, 0),   CGPointMake(-25, 0),
                            CGPointMake(0, 24),   CGPointMake(0, -25),
                            CGPointMake(24, -24), CGPointMake(100, 0)};

  for (CGPoint point : valid_points) {
    EXPECT_FALSE([cell.menuButton pointInside:point withEvent:nil]);
  }
}

// Ensures that a PriceNotificationTableViewItem can properly configure a
// PriceNotificaitonTableViewCell.
TEST_F(PriceNotificationsTableViewItemTest,
       PriceNotificationTableViewCellIsConfiguredByItem) {
  PriceNotificationsTableViewItem* item =
      [[PriceNotificationsTableViewItem alloc] initWithType:0];
  item.title = @"Test Item";
  item.entryURL = GURL("https://example.com/product/x");
  item.tracking = NO;
  item.loading = YES;
  item.currentPrice = @"$1.00";
  item.previousPrice = nil;
  item.productImage = UIGraphicsGetImageFromCurrentImageContext();
  PriceNotificationsTableViewCell* cell =
      [[PriceNotificationsTableViewCell alloc]
            initWithStyle:UITableViewCellStyleDefault
          reuseIdentifier:nil];

  [item configureCell:cell withStyler:[[ChromeTableViewStyler alloc] init]];

  EXPECT_NSEQ(item.title, cell.titleLabel.text);
  EXPECT_NSEQ(cell.URLLabel.text, @"example.com");
  EXPECT_TRUE(cell.isLoading);

  [cell prepareForReuse];
  EXPECT_FALSE(cell.isLoading);
}

// Ensures that the PriceNotificationsTableViewItem's Track Button correctly
// calculates its horizontal padding and width relative to the space available.
// The track button's width should be approximately between 17.5-21% of the
// PriceNotificationTableViewCell's width. In addition, the Track Button's side
// padding will range between 6 - 14 pts.
TEST_F(PriceNotificationsTableViewItemTest,
       PriceNotificationTrackButtonIsCorrectSize) {
  double parent_cell_width = 100;
  double button_text_width = 5;

  size_t padding = price_notifications::CalculateTrackButtonHorizontalPadding(
      parent_cell_width, button_text_width);
  price_notifications::WidthConstraintValues constraints =
      price_notifications::CalculateTrackButtonWidthConstraints(
          parent_cell_width, button_text_width, padding);

  EXPECT_EQ(padding, 6u);
  EXPECT_EQ(constraints.target_width, 17u);

  // Since the text width is large relative to the size of the button, the
  // minimum padding will be used and the button's width will be maximized.
  button_text_width = 10;
  padding = price_notifications::CalculateTrackButtonHorizontalPadding(
      parent_cell_width, button_text_width);
  constraints = price_notifications::CalculateTrackButtonWidthConstraints(
      parent_cell_width, button_text_width, padding);

  EXPECT_EQ(padding, 6u);
  EXPECT_EQ(constraints.target_width, constraints.max_width);

  // Since the text width is small relative to the size of the button, the
  // maximum padding will be used and the button's width will be
  parent_cell_width = 400;
  button_text_width = 15;
  padding = price_notifications::CalculateTrackButtonHorizontalPadding(
      parent_cell_width, button_text_width);
  constraints = price_notifications::CalculateTrackButtonWidthConstraints(
      parent_cell_width, button_text_width, padding);

  EXPECT_EQ(padding, 14u);
  EXPECT_EQ(constraints.target_width, 43u);
}