From 9df78c07f5a0e33850dbfb6b8653178d509e9ce1 Mon Sep 17 00:00:00 2001 From: yoanarios Date: Wed, 21 Jan 2026 11:08:39 -0500 Subject: [PATCH 1/4] Add unit test for UIFont extension --- firefox-ios/Client.xcodeproj/project.pbxproj | 14 ++- .../Extensions/UIFontExtensionsTests.swift | 118 ++++++++++++++++++ 2 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 firefox-ios/firefox-ios-tests/Tests/ClientTests/Extensions/UIFontExtensionsTests.swift diff --git a/firefox-ios/Client.xcodeproj/project.pbxproj b/firefox-ios/Client.xcodeproj/project.pbxproj index 6858bae185d36..be3985a6174aa 100644 --- a/firefox-ios/Client.xcodeproj/project.pbxproj +++ b/firefox-ios/Client.xcodeproj/project.pbxproj @@ -254,6 +254,8 @@ 212985E72A72B39D00546684 /* ThemeSettingsControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 212985E52A72B22800546684 /* ThemeSettingsControllerTests.swift */; }; 213047E62F2153B1007ECEDA /* PageZoomSettingsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 213047E52F2153AB007ECEDA /* PageZoomSettingsViewModelTests.swift */; }; 21304C8C2F217A59007ECEDA /* ThemeSettingsStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21304C8B2F217A59007ECEDA /* ThemeSettingsStateTests.swift */; }; + 213046B92F202F27007ECEDA /* UIFontExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 213046B82F202F27007ECEDA /* UIFontExtensionsTests.swift */; }; + 213046BB2F212BCC007ECEDA /* CGRectExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 213046BA2F212BCC007ECEDA /* CGRectExtensionsTests.swift */; }; 21371FA228A6C4A200BC3F37 /* OnboardingTelemetryUtilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21371FA128A6C4A200BC3F37 /* OnboardingTelemetryUtilityTests.swift */; }; 21371FA428AA7A8D00BC3F37 /* OnboardingViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21371FA328AA7A8D00BC3F37 /* OnboardingViewModelProtocol.swift */; }; 2137785D297F1F2800D01309 /* DownloadedFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2137785C297F1F2800D01309 /* DownloadedFile.swift */; }; @@ -1893,8 +1895,6 @@ E13C072D2C2189B80087E404 /* ToolbarActionConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13C072C2C2189B70087E404 /* ToolbarActionConfiguration.swift */; }; E13F8C342928194800BDC8B4 /* PhotonActionSheetSiteHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13F8C332928194800BDC8B4 /* PhotonActionSheetSiteHeaderView.swift */; }; E143BF652CE36FFD00A1D2D9 /* A11yTabTrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E143BF642CE36FF800A1D2D9 /* A11yTabTrayTests.swift */; }; - E1442FBF294782B6003680B0 /* CGRect+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1442FBE294782B6003680B0 /* CGRect+Extension.swift */; }; - E1442FC0294782B6003680B0 /* CGRect+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1442FBE294782B6003680B0 /* CGRect+Extension.swift */; }; E1442FCF294782D9003680B0 /* UIView+Screenshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1442FC4294782D7003680B0 /* UIView+Screenshot.swift */; }; E1442FD0294782D9003680B0 /* UIAlertController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1442FC5294782D7003680B0 /* UIAlertController+Extension.swift */; }; E1442FD1294782D9003680B0 /* UIModalPresentationStyle+Photon.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1442FC6294782D7003680B0 /* UIModalPresentationStyle+Photon.swift */; }; @@ -2940,6 +2940,8 @@ 212985E52A72B22800546684 /* ThemeSettingsControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeSettingsControllerTests.swift; sourceTree = ""; }; 213047E52F2153AB007ECEDA /* PageZoomSettingsViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageZoomSettingsViewModelTests.swift; sourceTree = ""; }; 21304C8B2F217A59007ECEDA /* ThemeSettingsStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeSettingsStateTests.swift; sourceTree = ""; }; + 213046B82F202F27007ECEDA /* UIFontExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIFontExtensionsTests.swift; sourceTree = ""; }; + 213046BA2F212BCC007ECEDA /* CGRectExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGRectExtensionsTests.swift; sourceTree = ""; }; 21371FA128A6C4A200BC3F37 /* OnboardingTelemetryUtilityTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingTelemetryUtilityTests.swift; sourceTree = ""; }; 21371FA328AA7A8D00BC3F37 /* OnboardingViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewModelProtocol.swift; sourceTree = ""; }; 2137785C297F1F2800D01309 /* DownloadedFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadedFile.swift; sourceTree = ""; }; @@ -10741,7 +10743,6 @@ E13C072C2C2189B70087E404 /* ToolbarActionConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarActionConfiguration.swift; sourceTree = ""; }; E13F8C332928194800BDC8B4 /* PhotonActionSheetSiteHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotonActionSheetSiteHeaderView.swift; sourceTree = ""; }; E143BF642CE36FF800A1D2D9 /* A11yTabTrayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = A11yTabTrayTests.swift; sourceTree = ""; }; - E1442FBE294782B6003680B0 /* CGRect+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGRect+Extension.swift"; sourceTree = ""; }; E1442FC4294782D7003680B0 /* UIView+Screenshot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Screenshot.swift"; sourceTree = ""; }; E1442FC5294782D7003680B0 /* UIAlertController+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIAlertController+Extension.swift"; sourceTree = ""; }; E1442FC6294782D7003680B0 /* UIModalPresentationStyle+Photon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIModalPresentationStyle+Photon.swift"; sourceTree = ""; }; @@ -12090,7 +12091,6 @@ isa = PBXGroup; children = ( 9609F4C926B57CE800F81493 /* Calendar+Extension.swift */, - E1442FBE294782B6003680B0 /* CGRect+Extension.swift */, 4393931F29AC6CE900DC5A85 /* EnvironmentValues+Extension.swift */, E1A6AB4528CA6A4C00EBEBDD /* String+Extension.swift */, E1442FC5294782D7003680B0 /* UIAlertController+Extension.swift */, @@ -13601,6 +13601,8 @@ 8A96C4B728F9DD0600B75884 /* Extensions */ = { isa = PBXGroup; children = ( + 213046BA2F212BCC007ECEDA /* CGRectExtensionsTests.swift */, + 213046B82F202F27007ECEDA /* UIFontExtensionsTests.swift */, 8ADED7EB27691351009C19E6 /* CalendarExtensionsTests.swift */, 2F44FA1A1A9D426A00FD20CC /* TestHashExtensions.swift */, A83E5B1C1C1DA8D80026D912 /* UIPasteboardExtensionsTests.swift */, @@ -18289,7 +18291,6 @@ E1442FDC2947836E003680B0 /* UIView+Extension.swift in Sources */, C874FB3A2660E8B900EBE86E /* CredentialProviderPresenter.swift in Sources */, 8A9F4F112DC8F5D7004644B9 /* TabsProvider.swift in Sources */, - E1442FC0294782B6003680B0 /* CGRect+Extension.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -18870,7 +18871,6 @@ 0E6C1E212C909AD7001A43BB /* PasswordGeneratorAction.swift in Sources */, F637D6732D8CBB6900C5C500 /* BasicAnimationControllerDelegate.swift in Sources */, 8A9F4F062DC8F592004644B9 /* TabsProvider.swift in Sources */, - E1442FBF294782B6003680B0 /* CGRect+Extension.swift in Sources */, C283EECE2E4D4DC7008EB540 /* RemoteSummarizerConfigSource.swift in Sources */, 96F8DA49280452CA00E53239 /* GleanPlumbContextProvider.swift in Sources */, 0E6C1E232C909E04001A43BB /* PasswordGeneratorState.swift in Sources */, @@ -19724,6 +19724,7 @@ 4A59B58AD11B5EE1F80BBDEB /* TestHistory.swift in Sources */, A83E5B1D1C1DA8D80026D912 /* UIPasteboardExtensionsTests.swift in Sources */, 8A01FE402DF0CE4E002C483B /* MockDateProvider.swift in Sources */, + 213046BB2F212BCC007ECEDA /* CGRectExtensionsTests.swift in Sources */, C27EF61F2EBA395A00BED719 /* MockLanguageSampleSource.swift in Sources */, 8A97E6EF2C584C4900F94793 /* AddressLocaleFeatureValidatorTests.swift in Sources */, C714D7B62E4673A300FC02E6 /* ShortcutsLibraryDiffableDataSourceTests.swift in Sources */, @@ -19780,6 +19781,7 @@ E1463D042982D0240074E16E /* NotificationManagerTests.swift in Sources */, 8AA0A6682CAC747500AC7EB3 /* HomepageDiffableDataSourceTests.swift in Sources */, C8E1BC0A28085AA700C62964 /* NimbusFeatureFlagLayerTests.swift in Sources */, + 213046B92F202F27007ECEDA /* UIFontExtensionsTests.swift in Sources */, 032CE5F62EBA0C04007CCC0D /* ToUExperiencePointsCalculatorTests.swift in Sources */, AAB5AF382EDDCF600051EF6E /* MockLocaleProvider.swift in Sources */, F80D53CF2A09A3350047ED14 /* RustSyncManagerTests.swift in Sources */, diff --git a/firefox-ios/firefox-ios-tests/Tests/ClientTests/Extensions/UIFontExtensionsTests.swift b/firefox-ios/firefox-ios-tests/Tests/ClientTests/Extensions/UIFontExtensionsTests.swift new file mode 100644 index 0000000000000..76ae17894ab7b --- /dev/null +++ b/firefox-ios/firefox-ios-tests/Tests/ClientTests/Extensions/UIFontExtensionsTests.swift @@ -0,0 +1,118 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + +import XCTest + +@testable import Client + +final class UIFontExtensionsTests: XCTestCase { + + // MARK: - bolded() + func testBolded_addsTraitBold() { + let font = UIFont.systemFont(ofSize: 16) + let boldFont = font.bolded() + + guard let boldFont else { + XCTFail("Expected valid bold font") + return + } + + XCTAssertTrue(boldFont.fontDescriptor.symbolicTraits.contains(.traitBold)) + } + + func testBolded_preservesFontSize() { + let originalSize: CGFloat = 24 + let font = UIFont.systemFont(ofSize: originalSize) + + guard let boldFont = font.bolded() else { + XCTFail("Expected valid bold font") + return + } + + XCTAssertEqual(boldFont.pointSize, originalSize) + } + + func testBolded_onAlreadyBoldFont_maintainsBold() { + let boldFont = UIFont.boldSystemFont(ofSize: 16) + + guard let doubleBoldFont = boldFont.bolded() else { + XCTFail("Expected valid bold font") + return + } + XCTAssertTrue(doubleBoldFont.fontDescriptor.symbolicTraits.contains(.traitBold)) + } + + // MARK: - italicized() + func testItalicized_addsTraitItalic() { + let font = UIFont.systemFont(ofSize: 16) + + guard let italicFont = font.italicized() else { + XCTFail("Expected valid italic font") + return + } + + XCTAssertTrue(italicFont.fontDescriptor.symbolicTraits.contains(.traitItalic)) + } + + func testItalicized_preservesFontSize() { + let originalSize: CGFloat = 18 + let font = UIFont.systemFont(ofSize: originalSize) + + guard let italicFont = font.italicized() else { + XCTFail("Expected valid italic font") + return + } + + XCTAssertEqual(italicFont.pointSize, originalSize) + } + + func testItalicized_onAlreadyItalicFont_maintainsItalic() { + let italicFont = UIFont.italicSystemFont(ofSize: 16) + guard let doubleItalicFont = italicFont.italicized() else { + XCTFail("Expected valid italic font") + return + } + + XCTAssertTrue(doubleItalicFont.fontDescriptor.symbolicTraits.contains(.traitItalic)) + } + + // MARK: - Combined traits + func testBolded_thenItalicized_hasBothTraits() { + let font = UIFont.systemFont(ofSize: 16) + + guard let boldFont = font.bolded(), + let boldItalicFont = boldFont.italicized() else { + XCTFail("Expected valid bold and italic font") + return + } + + let traits = boldItalicFont.fontDescriptor.symbolicTraits + XCTAssertTrue(traits.contains(.traitBold)) + XCTAssertTrue(traits.contains(.traitItalic)) + } + + func testItalicized_thenBolded_hasBothTraits() { + let font = UIFont.systemFont(ofSize: 16) + + guard let italicFont = font.italicized(), + let italicBoldFont = italicFont.bolded() else { + XCTFail("Expected valid bold and italic font") + return + } + + let traits = italicBoldFont.fontDescriptor.symbolicTraits + XCTAssertTrue(traits.contains(.traitItalic)) + XCTAssertTrue(traits.contains(.traitBold)) + + } + + func testCombinedTraits_preserveOriginalSize() { + let originalSize: CGFloat = 20 + let font = UIFont.systemFont(ofSize: originalSize) + + let styledFont = font.bolded()?.italicized() + XCTAssertNotNil(styledFont, "Expected valid bold and italic font") + XCTAssertEqual(styledFont?.pointSize, originalSize) + } +} From 0b6bfbbb2717e95b3fb0817dd305e844ee8dbeb7 Mon Sep 17 00:00:00 2001 From: yoanarios Date: Wed, 21 Jan 2026 11:09:21 -0500 Subject: [PATCH 2/4] Merge all CGRect extension and add unit test --- .../Shared/Extensions/UIImageExtensions.swift | 13 ++ .../Client/Extensions/CGRect+Extension.swift | 16 -- .../Widgets/GradientProgressBar.swift | 7 +- .../Frontend/Widgets/ToggleButton.swift | 1 + .../Extensions/CGRectExtensionsTests.swift | 196 ++++++++++++++++++ .../Extensions/UIFontExtensionsTests.swift | 2 - 6 files changed, 211 insertions(+), 24 deletions(-) delete mode 100644 firefox-ios/Client/Extensions/CGRect+Extension.swift create mode 100644 firefox-ios/firefox-ios-tests/Tests/ClientTests/Extensions/CGRectExtensionsTests.swift diff --git a/BrowserKit/Sources/Shared/Extensions/UIImageExtensions.swift b/BrowserKit/Sources/Shared/Extensions/UIImageExtensions.swift index 54deb932d4b19..5060a7202b5ab 100644 --- a/BrowserKit/Sources/Shared/Extensions/UIImageExtensions.swift +++ b/BrowserKit/Sources/Shared/Extensions/UIImageExtensions.swift @@ -12,6 +12,19 @@ extension CGRect { public init(size: CGSize) { self.init(origin: .zero, size: size) } + + public var center: CGPoint { + get { + return CGPoint(x: size.width / 2, y: size.height / 2) + } + set { + self.origin = CGPoint(x: newValue.x - size.width / 2, y: newValue.y - size.height / 2) + } + } + + public func updateWidth(byPercentage percentage: CGFloat) -> CGRect { + return CGRect(x: origin.x, y: origin.y, width: size.width * percentage, height: size.height) + } } extension Data { diff --git a/firefox-ios/Client/Extensions/CGRect+Extension.swift b/firefox-ios/Client/Extensions/CGRect+Extension.swift deleted file mode 100644 index 5790a6aa972cb..0000000000000 --- a/firefox-ios/Client/Extensions/CGRect+Extension.swift +++ /dev/null @@ -1,16 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/ - -import UIKit - -extension CGRect { - var center: CGPoint { - get { - return CGPoint(x: size.width / 2, y: size.height / 2) - } - set { - self.origin = CGPoint(x: newValue.x - size.width / 2, y: newValue.y - size.height / 2) - } - } -} diff --git a/firefox-ios/Client/Frontend/Widgets/GradientProgressBar.swift b/firefox-ios/Client/Frontend/Widgets/GradientProgressBar.swift index ee50bb3d65a72..d2ce70054a2a5 100644 --- a/firefox-ios/Client/Frontend/Widgets/GradientProgressBar.swift +++ b/firefox-ios/Client/Frontend/Widgets/GradientProgressBar.swift @@ -5,6 +5,7 @@ // ADAPTED FROM: work by Felix Mau on 01.03.17. import UIKit +import Shared open class GradientProgressBar: UIProgressView { private struct DefaultValues { @@ -178,9 +179,3 @@ open class GradientProgressBar: UIProgressView { updateAlphaMaskLayerWidth(animated: animated) } } - -extension CGRect { - func updateWidth(byPercentage percentage: CGFloat) -> CGRect { - return CGRect(x: origin.x, y: origin.y, width: size.width * percentage, height: size.height) - } -} diff --git a/firefox-ios/Client/Frontend/Widgets/ToggleButton.swift b/firefox-ios/Client/Frontend/Widgets/ToggleButton.swift index 50786b3b9f6c9..b9d7cfe699101 100644 --- a/firefox-ios/Client/Frontend/Widgets/ToggleButton.swift +++ b/firefox-ios/Client/Frontend/Widgets/ToggleButton.swift @@ -4,6 +4,7 @@ import UIKit import Common +import Shared private struct UX { // The amount of pixels the toggle button will expand over the normal size. diff --git a/firefox-ios/firefox-ios-tests/Tests/ClientTests/Extensions/CGRectExtensionsTests.swift b/firefox-ios/firefox-ios-tests/Tests/ClientTests/Extensions/CGRectExtensionsTests.swift new file mode 100644 index 0000000000000..d99dccfc92988 --- /dev/null +++ b/firefox-ios/firefox-ios-tests/Tests/ClientTests/Extensions/CGRectExtensionsTests.swift @@ -0,0 +1,196 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + +import XCTest + +@testable import Client + +final class CGRectExtensionsTests: XCTestCase { + // MARK: - init(width:height:) + + func testInitWithWidthHeight_createsRectAtOrigin() { + let rect = CGRect(width: 100, height: 50) + + XCTAssertEqual(rect.origin.x, 0) + XCTAssertEqual(rect.origin.y, 0) + XCTAssertEqual(rect.size.width, 100) + XCTAssertEqual(rect.size.height, 50) + } + + func testInitWithWidthHeight_withZeroValues() { + let rect = CGRect(width: 0, height: 0) + + XCTAssertEqual(rect, .zero) + } + + func testInitWithWidthHeight_withNegativeValues() { + let rect = CGRect(width: -10, height: -20) + + XCTAssertEqual(rect.size.width, -10) + XCTAssertEqual(rect.size.height, -20) + } + + // MARK: - init(size:) + + func testInitWithSize_createsRectAtZeroOrigin() { + let size = CGSize(width: 200, height: 150) + let rect = CGRect(size: size) + + XCTAssertEqual(rect.origin, .zero) + XCTAssertEqual(rect.size, size) + } + + func testInitWithSize_withEmptySize() { + let rect = CGRect(size: .zero) + + XCTAssertEqual(rect, .zero) + } + + // MARK: - center (getter) + + func testCenterGetter_returnsCorrectCenter() { + let rect = CGRect(x: 0, y: 0, width: 100, height: 50) + + let center = rect.center + + XCTAssertEqual(center.x, 50) + XCTAssertEqual(center.y, 25) + } + + func testCenterGetter_withNonZeroOrigin() { + let rect = CGRect(x: 20, y: 30, width: 100, height: 50) + + let center = rect.center + + // Center should be relative to size, not absolute position + XCTAssertEqual(center.x, 50) + XCTAssertEqual(center.y, 25) + } + + func testCenterGetter_withZeroRect() { + let rect = CGRect.zero + + let center = rect.center + + XCTAssertEqual(center, .zero) + } + + // MARK: - center (setter) + + func testCenterSetter_updatesOrigin() { + var rect = CGRect(x: 0, y: 0, width: 100, height: 50) + + rect.center = CGPoint(x: 150, y: 100) + + // Origin should be adjusted so center is at (150, 100) + XCTAssertEqual(rect.origin.x, 100) // 150 - 50 (half width) + XCTAssertEqual(rect.origin.y, 75) // 100 - 25 (half height) + XCTAssertEqual(rect.size.width, 100) + XCTAssertEqual(rect.size.height, 50) + } + + func testCenterSetter_preservesSize() { + var rect = CGRect(x: 0, y: 0, width: 200, height: 100) + let originalSize = rect.size + + rect.center = CGPoint(x: 50, y: 50) + + XCTAssertEqual(rect.size, originalSize) + } + + func testCenterSetter_withZeroCenter() { + var rect = CGRect(x: 100, y: 100, width: 80, height: 60) + + rect.center = .zero + + // Expected 80 / 2 = 40 + XCTAssertEqual(rect.origin.x, -40) + // Expected 60 / 2 = 30 + XCTAssertEqual(rect.origin.y, -30) + } + + // MARK: - updateWidth(byPercentage:) + + func testUpdateWidth_with100Percent_returnsOriginalWidth() { + let rect = CGRect(x: 10, y: 20, width: 100, height: 50) + + let updated = rect.updateWidth(byPercentage: 1.0) + + XCTAssertEqual(updated.size.width, 100) + XCTAssertEqual(updated.origin, rect.origin) + XCTAssertEqual(updated.size.height, rect.size.height) + } + + func testUpdateWidth_with50Percent_halvesWidth() { + let rect = CGRect(x: 10, y: 20, width: 100, height: 50) + + let updated = rect.updateWidth(byPercentage: 0.5) + + XCTAssertEqual(updated.size.width, 50) + XCTAssertEqual(updated.origin, rect.origin) + XCTAssertEqual(updated.size.height, rect.size.height) + } + + func testUpdateWidth_with200Percent_doublesWidth() { + let rect = CGRect(x: 5, y: 10, width: 50, height: 30) + + let updated = rect.updateWidth(byPercentage: 2.0) + + XCTAssertEqual(updated.size.width, 100) + XCTAssertEqual(updated.origin, rect.origin) + XCTAssertEqual(updated.size.height, rect.size.height) + } + + func testUpdateWidth_withZeroPercent_returnsZeroWidth() { + let rect = CGRect(x: 0, y: 0, width: 100, height: 50) + + let updated = rect.updateWidth(byPercentage: 0.0) + + XCTAssertEqual(updated.size.width, 0) + XCTAssertEqual(updated.size.height, rect.size.height) + } + + func testUpdateWidth_preservesOriginAndHeight() { + let rect = CGRect(x: 25, y: 35, width: 80, height: 60) + + let updated = rect.updateWidth(byPercentage: 0.75) + + XCTAssertEqual(updated.origin.x, 25) + XCTAssertEqual(updated.origin.y, 35) + XCTAssertEqual(updated.size.height, 60) + // Expected 80 * 0.75 = 60 + XCTAssertEqual(updated.size.width, 60) + } + + func testUpdateWidth_withNegativePercentage() { + let rect = CGRect(x: 0, y: 0, width: 100, height: 50) + + let updated = rect.updateWidth(byPercentage: -0.5) + + XCTAssertEqual(updated.size.width, -50) + } + + // MARK: - Integration Tests + + func testCombinedOperations_initWithSizeThenUpdateCenter() { + var rect = CGRect(size: CGSize(width: 100, height: 50)) + rect.center = CGPoint(x: 200, y: 100) + + XCTAssertEqual(rect.origin.x, 150) + XCTAssertEqual(rect.origin.y, 75) + XCTAssertEqual(rect.size.width, 100) + XCTAssertEqual(rect.size.height, 50) + } + + func testCombinedOperations_updateWidthThenGetCenter() { + let rect = CGRect(x: 0, y: 0, width: 100, height: 50) + let updated = rect.updateWidth(byPercentage: 0.5) + + let center = updated.center + + // Half of new width and height (50) + XCTAssertEqual(center.x, 25) + XCTAssertEqual(center.y, 25) + } +} diff --git a/firefox-ios/firefox-ios-tests/Tests/ClientTests/Extensions/UIFontExtensionsTests.swift b/firefox-ios/firefox-ios-tests/Tests/ClientTests/Extensions/UIFontExtensionsTests.swift index 76ae17894ab7b..a5a7e6b85b3ca 100644 --- a/firefox-ios/firefox-ios-tests/Tests/ClientTests/Extensions/UIFontExtensionsTests.swift +++ b/firefox-ios/firefox-ios-tests/Tests/ClientTests/Extensions/UIFontExtensionsTests.swift @@ -7,7 +7,6 @@ import XCTest @testable import Client final class UIFontExtensionsTests: XCTestCase { - // MARK: - bolded() func testBolded_addsTraitBold() { let font = UIFont.systemFont(ofSize: 16) @@ -104,7 +103,6 @@ final class UIFontExtensionsTests: XCTestCase { let traits = italicBoldFont.fontDescriptor.symbolicTraits XCTAssertTrue(traits.contains(.traitItalic)) XCTAssertTrue(traits.contains(.traitBold)) - } func testCombinedTraits_preserveOriginalSize() { From 2df3dd88718fbccb9edfabbaee0c891130be191a Mon Sep 17 00:00:00 2001 From: yoanarios Date: Wed, 21 Jan 2026 14:51:50 -0500 Subject: [PATCH 3/4] Create own file for CGRectExtension and leave updateWith func where is used --- .../Shared/Extensions/CGRectExtensions.swift | 24 +++++++++++++++++++ .../Shared/Extensions/UIImageExtensions.swift | 23 ------------------ .../Widgets/GradientProgressBar.swift | 7 +++++- 3 files changed, 30 insertions(+), 24 deletions(-) create mode 100644 BrowserKit/Sources/Shared/Extensions/CGRectExtensions.swift diff --git a/BrowserKit/Sources/Shared/Extensions/CGRectExtensions.swift b/BrowserKit/Sources/Shared/Extensions/CGRectExtensions.swift new file mode 100644 index 0000000000000..f04e36b928538 --- /dev/null +++ b/BrowserKit/Sources/Shared/Extensions/CGRectExtensions.swift @@ -0,0 +1,24 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + +import UIKit + +extension CGRect { + public init(width: CGFloat, height: CGFloat) { + self.init(x: 0, y: 0, width: width, height: height) + } + + public init(size: CGSize) { + self.init(origin: .zero, size: size) + } + + public var center: CGPoint { + get { + return CGPoint(x: size.width / 2, y: size.height / 2) + } + set { + self.origin = CGPoint(x: newValue.x - size.width / 2, y: newValue.y - size.height / 2) + } + } +} diff --git a/BrowserKit/Sources/Shared/Extensions/UIImageExtensions.swift b/BrowserKit/Sources/Shared/Extensions/UIImageExtensions.swift index 5060a7202b5ab..1d3bbae453535 100644 --- a/BrowserKit/Sources/Shared/Extensions/UIImageExtensions.swift +++ b/BrowserKit/Sources/Shared/Extensions/UIImageExtensions.swift @@ -4,29 +4,6 @@ import UIKit -extension CGRect { - public init(width: CGFloat, height: CGFloat) { - self.init(x: 0, y: 0, width: width, height: height) - } - - public init(size: CGSize) { - self.init(origin: .zero, size: size) - } - - public var center: CGPoint { - get { - return CGPoint(x: size.width / 2, y: size.height / 2) - } - set { - self.origin = CGPoint(x: newValue.x - size.width / 2, y: newValue.y - size.height / 2) - } - } - - public func updateWidth(byPercentage percentage: CGFloat) -> CGRect { - return CGRect(x: origin.x, y: origin.y, width: size.width * percentage, height: size.height) - } -} - extension Data { public var isGIF: Bool { return [0x47, 0x49, 0x46].elementsEqual(prefix(3)) diff --git a/firefox-ios/Client/Frontend/Widgets/GradientProgressBar.swift b/firefox-ios/Client/Frontend/Widgets/GradientProgressBar.swift index d2ce70054a2a5..5153c2adf7e9a 100644 --- a/firefox-ios/Client/Frontend/Widgets/GradientProgressBar.swift +++ b/firefox-ios/Client/Frontend/Widgets/GradientProgressBar.swift @@ -5,7 +5,6 @@ // ADAPTED FROM: work by Felix Mau on 01.03.17. import UIKit -import Shared open class GradientProgressBar: UIProgressView { private struct DefaultValues { @@ -179,3 +178,9 @@ open class GradientProgressBar: UIProgressView { updateAlphaMaskLayerWidth(animated: animated) } } + +extension CGRect { + public func updateWidth(byPercentage percentage: CGFloat) -> CGRect { + return CGRect(x: origin.x, y: origin.y, width: size.width * percentage, height: size.height) + } +} From dbe606c5fae829bf5b31cd4da9168b7b64014a2f Mon Sep 17 00:00:00 2001 From: yoanarios Date: Thu, 22 Jan 2026 13:25:08 -0500 Subject: [PATCH 4/4] Revert public change --- firefox-ios/Client/Frontend/Widgets/GradientProgressBar.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firefox-ios/Client/Frontend/Widgets/GradientProgressBar.swift b/firefox-ios/Client/Frontend/Widgets/GradientProgressBar.swift index 5153c2adf7e9a..ee50bb3d65a72 100644 --- a/firefox-ios/Client/Frontend/Widgets/GradientProgressBar.swift +++ b/firefox-ios/Client/Frontend/Widgets/GradientProgressBar.swift @@ -180,7 +180,7 @@ open class GradientProgressBar: UIProgressView { } extension CGRect { - public func updateWidth(byPercentage percentage: CGFloat) -> CGRect { + func updateWidth(byPercentage percentage: CGFloat) -> CGRect { return CGRect(x: origin.x, y: origin.y, width: size.width * percentage, height: size.height) } }