Skip to content

Commit

Permalink
Merge branch 'main' of ssh://github.com/bitwarden/ios into PM-16141/g…
Browse files Browse the repository at this point in the history
…enerator-action-card
  • Loading branch information
ezimet-livefront committed Jan 15, 2025
2 parents aa67556 + 9205ace commit aa27099
Show file tree
Hide file tree
Showing 10 changed files with 62 additions and 13 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,9 @@ jobs:
ref: ${{ github.event.pull_request.head.sha }}

- name: Scan with SonarCloud
uses: sonarsource/sonarcloud-github-action@383f7e52eae3ab0510c3cb0e7d9d150bbaeab838 # v3.1.0
uses: sonarsource/sonarqube-scan-action@bfd4e558cda28cda6b5defafb9232d191be8c203 # v4.2.1
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
args: >
-Dsonar.organization=${{ github.repository_owner }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1096,3 +1096,4 @@
"ExportFailed" = "Export failed";
"ThereHasBeenAnIssueExportingItems" = "There has been an issue exporting items.";
"AreYouSureYouWantToCancelTheExportProcessQuestionMark" = "Are you sure you want to cancel the export process?";
"PleaseDoNotCloseTheApp" = "Please do not close the app.";
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class ImportCXPProcessor: StateProcessor<ImportCXPState, Void, ImportCXPEffect>
typealias Services = HasConfigService
& HasErrorReporter
& HasImportCiphersRepository
& HasPolicyService
& HasStateService

// MARK: Private Properties
Expand Down Expand Up @@ -68,6 +69,10 @@ class ImportCXPProcessor: StateProcessor<ImportCXPState, Void, ImportCXPEffect>
state.status = .failure(message: Localizations.importingFromAnotherProviderIsNotAvailableForThisDevice)
return
}
if await services.policyService.policyAppliesToUser(.personalOwnership) {
state.isFeatureUnavailable = true
state.status = .failure(message: Localizations.personalOwnershipPolicyInEffect)
}
}

/// Starts the import process.
Expand Down Expand Up @@ -110,7 +115,7 @@ class ImportCXPProcessor: StateProcessor<ImportCXPState, Void, ImportCXPEffect>

/// Shows the alert confirming the user wants to import logins later.
private func cancelWithConfirmation() {
guard !state.isFeatureUnvailable else {
guard !state.isFeatureUnavailable else {
coordinator.navigate(to: .dismiss)
return
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class ImportCXPProcessorTests: BitwardenTestCase {
var coordinator: MockCoordinator<ImportCXPRoute, Void>!
var errorReporter: MockErrorReporter!
var importCiphersRepository: MockImportCiphersRepository!
var policyService: MockPolicyService!
var state: ImportCXPState!
var stateService: MockStateService!
var subject: ImportCXPProcessor!
Expand All @@ -24,6 +25,7 @@ class ImportCXPProcessorTests: BitwardenTestCase {
coordinator = MockCoordinator<ImportCXPRoute, Void>()
errorReporter = MockErrorReporter()
importCiphersRepository = MockImportCiphersRepository()
policyService = MockPolicyService()
state = ImportCXPState()
stateService = MockStateService()
subject = ImportCXPProcessor(
Expand All @@ -32,6 +34,7 @@ class ImportCXPProcessorTests: BitwardenTestCase {
configService: configService,
errorReporter: errorReporter,
importCiphersRepository: importCiphersRepository,
policyService: policyService,
stateService: stateService
),
state: state
Expand All @@ -45,6 +48,7 @@ class ImportCXPProcessorTests: BitwardenTestCase {
coordinator = nil
errorReporter = nil
importCiphersRepository = nil
policyService = nil
state = nil
stateService = nil
subject = nil
Expand All @@ -65,7 +69,30 @@ class ImportCXPProcessorTests: BitwardenTestCase {
}

/// `perform(_:)` with `.appeared` sets the status as `.failure` with a message
/// when the feature flag `.cxpImportMobile` is not enabled.
/// when the feature flag `.cxpImportMobile` is enabled. but `.personalOwnership`
/// policy applies to user.
@MainActor
func test_perform_appearedPersonalOwnership() async throws {
guard #available(iOS 18.2, *) else {
throw XCTSkip("CXP Import feature is not available on this device")
}

configService.featureFlagsBool[.cxpImportMobile] = true
policyService.policyAppliesToUserResult[.personalOwnership] = true

await subject.perform(.appeared)

guard case let .failure(message) = subject.state.status else {
XCTFail("Status should be failure")
return
}
XCTAssertEqual(message, Localizations.personalOwnershipPolicyInEffect)
XCTAssertTrue(subject.state.isFeatureUnavailable)
}

/// `perform(_:)` with `.appeared` doesn't set the status as `.failure`
/// when the feature flag `.cxpImportMobile` is enabled and `.personalOwnership`
/// policy doesn't apply to user.
@MainActor
func test_perform_appearedFeatureFlagEnabled() async throws {
guard #available(iOS 18.2, *) else {
Expand All @@ -82,7 +109,7 @@ class ImportCXPProcessorTests: BitwardenTestCase {
/// `perform(_:)` with `.cancel` with feature available shows confirmation and navigates to dismiss.
@MainActor
func test_perform_cancel() async throws {
subject.state.isFeatureUnvailable = false
subject.state.isFeatureUnavailable = false
let task = Task {
await subject.perform(.cancel)
}
Expand All @@ -108,7 +135,7 @@ class ImportCXPProcessorTests: BitwardenTestCase {
/// doesn't navigate to dismiss if the user cancels the confirmation dialog.
@MainActor
func test_perform_cancelNoConfirmation() async throws {
subject.state.isFeatureUnvailable = false
subject.state.isFeatureUnavailable = false
let task = Task {
await subject.perform(.cancel)
}
Expand All @@ -128,7 +155,7 @@ class ImportCXPProcessorTests: BitwardenTestCase {
/// `perform(_:)` with `.cancel` with feature unavailable navigates to dismiss.
@MainActor
func test_perform_cancelFeatureUnavailable() async throws {
subject.state.isFeatureUnvailable = true
subject.state.isFeatureUnavailable = true
let task = Task {
await subject.perform(.cancel)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ struct ImportCXPState: Equatable, Sendable {
var credentialImportToken: UUID?

/// Whether the CXP import feature is available.
var isFeatureUnvailable: Bool = false
var isFeatureUnavailable: Bool = false

/// The title of the main button.
var mainButtonTitle: String {
Expand Down Expand Up @@ -62,7 +62,7 @@ struct ImportCXPState: Equatable, Sendable {
case .start:
Localizations.startImportCXPDescriptionLong
case .importing:
""
Localizations.pleaseDoNotCloseTheApp
case let .success(total, _):
Localizations.itemsSuccessfullyImported(total)
case let .failure(message):
Expand All @@ -83,7 +83,7 @@ struct ImportCXPState: Equatable, Sendable {
case .success:
Localizations.importSuccessful
case .failure:
isFeatureUnvailable ? Localizations.importNotAvailable : Localizations.importFailed
isFeatureUnavailable ? Localizations.importNotAvailable : Localizations.importFailed
}
}

Expand All @@ -99,7 +99,7 @@ struct ImportCXPState: Equatable, Sendable {

/// Whether to show the main button.
var showMainButton: Bool {
status != .importing || isFeatureUnvailable
status != .importing && !isFeatureUnavailable
}

/// The current status of the import process.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class ImportCXPStateTests: BitwardenTestCase {
XCTAssertEqual(subject.message, Localizations.startImportCXPDescriptionLong)

subject.status = .importing
XCTAssertEqual(subject.message, "")
XCTAssertEqual(subject.message, Localizations.pleaseDoNotCloseTheApp)

subject.status = .success(totalImportedCredentials: 1, importedResults: [])
XCTAssertEqual(subject.message, Localizations.itemsSuccessfullyImported(1))
Expand All @@ -84,7 +84,7 @@ class ImportCXPStateTests: BitwardenTestCase {
subject.status = .failure(message: "Something went wrong")
XCTAssertEqual(subject.title, Localizations.importFailed)

subject.isFeatureUnvailable = true
subject.isFeatureUnavailable = true
XCTAssertEqual(subject.title, Localizations.importNotAvailable)
}

Expand Down Expand Up @@ -117,4 +117,20 @@ class ImportCXPStateTests: BitwardenTestCase {
subject.status = .failure(message: "Something went wrong")
XCTAssertTrue(subject.showMainButton)
}

/// `getter:showMainButton` returns `false` when feature unavailable.
func test_showMainButton_featureUnavailable() {
subject.isFeatureUnavailable = true
subject.status = .start
XCTAssertFalse(subject.showMainButton)

subject.status = .importing
XCTAssertFalse(subject.showMainButton)

subject.status = .success(totalImportedCredentials: 1, importedResults: [])
XCTAssertFalse(subject.showMainButton)

subject.status = .failure(message: "Something went wrong")
XCTAssertFalse(subject.showMainButton)
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class ImportCXPCoordinator: Coordinator, HasStackNavigator {
typealias Services = HasConfigService
& HasErrorReporter
& HasImportCiphersRepository
& HasPolicyService
& HasStateService

// MARK: Private Properties
Expand Down

0 comments on commit aa27099

Please sign in to comment.