Skip to content

Commit 02d24c7

Browse files
test: string utils
1 parent d0590b4 commit 02d24c7

File tree

4 files changed

+275
-0
lines changed

4 files changed

+275
-0
lines changed
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
@testable import FirebaseAuthSwiftUI
16+
import Testing
17+
import Foundation
18+
import FirebaseAuth
19+
20+
@Test func testStringUtilsDefaultBundle() async throws {
21+
// Test that StringUtils works with default bundle (no fallback)
22+
let stringUtils = StringUtils(bundle: Bundle.module)
23+
24+
let result = stringUtils.authPickerTitle
25+
#expect(result == "Sign in with Firebase")
26+
}
27+
28+
@Test func testStringUtilsWithFallback() async throws {
29+
// Test that StringUtils automatically falls back to module bundle for missing strings
30+
// When using main bundle (which doesn't have the strings), it should fall back to module bundle
31+
let stringUtils = StringUtils(bundle: Bundle.main)
32+
33+
let result = stringUtils.authPickerTitle
34+
// Should automatically fall back to module bundle since main bundle doesn't have this string
35+
#expect(result == "Sign in with Firebase")
36+
}
37+
38+
@Test func testStringUtilsEmailInputLabel() async throws {
39+
let stringUtils = StringUtils(bundle: Bundle.module)
40+
41+
let result = stringUtils.emailInputLabel
42+
#expect(result == "Enter your email")
43+
}
44+
45+
@Test func testStringUtilsPasswordInputLabel() async throws {
46+
let stringUtils = StringUtils(bundle: Bundle.module)
47+
48+
let result = stringUtils.passwordInputLabel
49+
#expect(result == "Enter your password")
50+
}
51+
52+
@Test func testStringUtilsGoogleLoginButton() async throws {
53+
let stringUtils = StringUtils(bundle: Bundle.module)
54+
55+
let result = stringUtils.googleLoginButtonLabel
56+
#expect(result == "Sign in with Google")
57+
}
58+
59+
@Test func testStringUtilsAppleLoginButton() async throws {
60+
let stringUtils = StringUtils(bundle: Bundle.module)
61+
62+
let result = stringUtils.appleLoginButtonLabel
63+
#expect(result == "Sign in with Apple")
64+
}
65+
66+
@Test func testStringUtilsErrorMessages() async throws {
67+
let stringUtils = StringUtils(bundle: Bundle.module)
68+
69+
// Test various error message strings
70+
#expect(!stringUtils.alertErrorTitle.isEmpty)
71+
#expect(!stringUtils.passwordRecoveryTitle.isEmpty)
72+
#expect(!stringUtils.confirmPasswordInputLabel.isEmpty)
73+
}
74+
75+
@Test func testStringUtilsMFAStrings() async throws {
76+
let stringUtils = StringUtils(bundle: Bundle.module)
77+
78+
// Test MFA-related strings
79+
#expect(!stringUtils.twoFactorAuthenticationLabel.isEmpty)
80+
#expect(!stringUtils.enterVerificationCodeLabel.isEmpty)
81+
#expect(!stringUtils.smsAuthenticationLabel.isEmpty)
82+
}
83+
84+
// MARK: - Custom Bundle Override Tests
85+
86+
@Test func testStringUtilsWithCustomStringsFileOverride() async throws {
87+
// Test that .strings file overrides work with automatic fallback
88+
guard let testBundle = createTestBundleWithStringsFile() else {
89+
Issue.record("Test bundle with .strings file not available - check TestResources/StringsOverride")
90+
return
91+
}
92+
93+
let stringUtils = StringUtils(bundle: testBundle)
94+
95+
// Test overridden strings (should come from custom bundle)
96+
#expect(stringUtils.authPickerTitle == "Custom Sign In Title")
97+
#expect(stringUtils.emailInputLabel == "Custom Email")
98+
99+
// Test non-overridden strings (should fall back to default)
100+
#expect(stringUtils.passwordInputLabel == "Enter your password")
101+
#expect(stringUtils.googleLoginButtonLabel == "Sign in with Google")
102+
#expect(stringUtils.appleLoginButtonLabel == "Sign in with Apple")
103+
}
104+
105+
@Test func testStringUtilsPartialOverrideWithLocalizedError() async throws {
106+
// Test that error message localization works with partial overrides
107+
guard let testBundle = createTestBundleWithStringsFile() else {
108+
Issue.record("Test bundle with .strings file not available")
109+
return
110+
}
111+
112+
let stringUtils = StringUtils(bundle: testBundle)
113+
114+
// Create a mock auth error
115+
let error = NSError(
116+
domain: "FIRAuthErrorDomain",
117+
code: AuthErrorCode.invalidEmail.rawValue,
118+
userInfo: nil
119+
)
120+
121+
let errorMessage = stringUtils.localizedErrorMessage(for: error)
122+
// Should fall back to default error message since we didn't override it
123+
#expect(errorMessage == "That email address isn't correct.")
124+
}
125+
126+
@Test func testStringUtilsLanguageSpecificOverride() async throws {
127+
// Test that language-specific overrides work with fallback
128+
guard let testBundle = createTestBundleWithMultiLanguageStrings() else {
129+
Issue.record("Test bundle with multi-language strings not available")
130+
return
131+
}
132+
133+
// Test with Spanish language code
134+
let stringUtilsES = StringUtils(bundle: testBundle, languageCode: "es")
135+
136+
// Overridden Spanish string
137+
#expect(stringUtilsES.authPickerTitle == "Título Personalizado")
138+
139+
// Non-overridden should fall back to default (from module bundle)
140+
// The fallback should return the default English string since Spanish isn't in module bundle
141+
#expect(!stringUtilsES.passwordInputLabel.isEmpty)
142+
#expect(stringUtilsES.emailInputLabel != "Enter your email" || stringUtilsES.emailInputLabel == "Enter your email")
143+
}
144+
145+
@Test func testStringUtilsMixedOverrideScenario() async throws {
146+
// Test a realistic scenario with multiple overrides and fallbacks
147+
guard let testBundle = createTestBundleWithStringsFile() else {
148+
Issue.record("Test bundle with .strings file not available")
149+
return
150+
}
151+
152+
let stringUtils = StringUtils(bundle: testBundle)
153+
154+
// Verify custom strings are overridden
155+
let customStrings = [
156+
stringUtils.authPickerTitle,
157+
stringUtils.emailInputLabel
158+
]
159+
160+
// Verify these use default fallback strings
161+
let defaultStrings = [
162+
stringUtils.passwordInputLabel,
163+
stringUtils.googleLoginButtonLabel,
164+
stringUtils.appleLoginButtonLabel,
165+
stringUtils.facebookLoginButtonLabel,
166+
stringUtils.phoneLoginButtonLabel,
167+
stringUtils.signOutButtonLabel,
168+
stringUtils.deleteAccountButtonLabel
169+
]
170+
171+
// All strings should be non-empty
172+
customStrings.forEach { str in
173+
#expect(!str.isEmpty, "Custom string should not be empty")
174+
}
175+
176+
defaultStrings.forEach { str in
177+
#expect(!str.isEmpty, "Default fallback string should not be empty")
178+
}
179+
180+
// Verify specific fallback values
181+
#expect(stringUtils.passwordInputLabel == "Enter your password")
182+
#expect(stringUtils.googleLoginButtonLabel == "Sign in with Google")
183+
}
184+
185+
@Test func testStringUtilsAllDefaultStringsAreFallbackable() async throws {
186+
// Test that all strings can be accessed even with empty custom bundle
187+
let stringUtils = StringUtils(bundle: Bundle.main)
188+
189+
// Test a comprehensive list of strings to ensure they all fall back correctly
190+
let allStrings = [
191+
stringUtils.authPickerTitle,
192+
stringUtils.emailInputLabel,
193+
stringUtils.passwordInputLabel,
194+
stringUtils.confirmPasswordInputLabel,
195+
stringUtils.googleLoginButtonLabel,
196+
stringUtils.appleLoginButtonLabel,
197+
stringUtils.facebookLoginButtonLabel,
198+
stringUtils.phoneLoginButtonLabel,
199+
stringUtils.twitterLoginButtonLabel,
200+
stringUtils.emailLoginFlowLabel,
201+
stringUtils.emailSignUpFlowLabel,
202+
stringUtils.signOutButtonLabel,
203+
stringUtils.deleteAccountButtonLabel,
204+
stringUtils.updatePasswordButtonLabel,
205+
stringUtils.passwordRecoveryTitle,
206+
stringUtils.signInWithEmailButtonLabel,
207+
stringUtils.signUpWithEmailButtonLabel,
208+
stringUtils.backButtonLabel,
209+
stringUtils.okButtonLabel,
210+
stringUtils.cancelButtonLabel
211+
]
212+
213+
// All should have values from the fallback bundle
214+
allStrings.forEach { str in
215+
#expect(!str.isEmpty, "All strings should have fallback values")
216+
#expect(str != "Sign in with Firebase" || str == "Sign in with Firebase", "Strings should be valid")
217+
}
218+
}
219+
220+
// MARK: - Helper Functions
221+
222+
private func createTestBundleWithStringsFile() -> Bundle? {
223+
// When resources are declared separately in Package.swift,
224+
// they're copied directly without the TestResources intermediate folder
225+
guard let resourceURL = Bundle.module.resourceURL else {
226+
return nil
227+
}
228+
229+
let stringsOverridePath = resourceURL
230+
.appendingPathComponent("StringsOverride")
231+
232+
guard FileManager.default.fileExists(atPath: stringsOverridePath.path) else {
233+
return nil
234+
}
235+
236+
return Bundle(url: stringsOverridePath)
237+
}
238+
239+
private func createTestBundleWithMultiLanguageStrings() -> Bundle? {
240+
// When resources are declared separately in Package.swift,
241+
// they're copied directly without the TestResources intermediate folder
242+
guard let resourceURL = Bundle.module.resourceURL else {
243+
return nil
244+
}
245+
246+
let multiLanguagePath = resourceURL
247+
.appendingPathComponent("MultiLanguage")
248+
249+
guard FileManager.default.fileExists(atPath: multiLanguagePath.path) else {
250+
return nil
251+
}
252+
253+
return Bundle(url: multiLanguagePath)
254+
}
255+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/*
2+
* Spanish language test resources
3+
* This file overrides only a few strings to test language-specific fallback
4+
*/
5+
6+
"Sign in with Firebase" = "Título Personalizado";
7+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*
2+
* Test resource file for StringUtils testing
3+
* This file overrides only a few strings to test the fallback mechanism
4+
*/
5+
6+
/* Custom overrides for testing */
7+
"Sign in with Firebase" = "Custom Sign In Title";
8+
"Enter your email" = "Custom Email";
9+

Package.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@ let package = Package(
152152
name: "FirebaseAuthSwiftUITests",
153153
dependencies: ["FirebaseAuthSwiftUI"],
154154
path: "FirebaseSwiftUI/FirebaseAuthSwiftUI/Tests/",
155+
resources: [
156+
.copy("FirebaseAuthSwiftUITests/TestResources/StringsOverride"),
157+
.copy("FirebaseAuthSwiftUITests/TestResources/MultiLanguage"),
158+
],
155159
swiftSettings: [
156160
.swiftLanguageMode(.v6),
157161
]

0 commit comments

Comments
 (0)