Skip to content

Conversation

@dnicolson
Copy link
Contributor

@dnicolson dnicolson commented Nov 29, 2025

User description

This fixes a crash because a Realm instance is expected:

self.game = game.isFrozen ? game : game.freeze()

This only occurs in the Simulator with an empty library:

if safeGames.isEmpty && AppState.shared.isSimulator {


PR Type

Bug fix


Description

  • Fix Simulator crash when library is empty

  • Ensure Realm instance exists in mock game generation

  • Wrap mock game creation in Realm write transaction

  • Properly add generated games to Realm database


Diagram Walkthrough

flowchart LR
  A["mockGenerate method"] --> B["Create in-memory Realm"]
  B --> C["Write transaction"]
  C --> D["Create mock games"]
  D --> E["Add to Realm"]
  E --> F["Return games array"]
Loading

File Walkthrough

Relevant files
Bug fix
PVGame.swift
Add Realm transaction to mock game generation                       

PVLibrary/Sources/PVRealm/RealmPlatform/Entities/PVGame.swift

  • Initialize in-memory Realm instance in mockGenerate method
  • Wrap mock game creation in realm.write transaction block
  • Add created games to Realm using realm.add(game)
  • Fix publishDate to use current index instead of count
+14/-7   

@qodo-code-review
Copy link

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Unhandled fatal errors

Description: Force-unwrapping Realm initialization and write transaction with 'try!' can crash the app
(denial of service) if in-memory Realm configuration fails or a write error occurs;
replace with handled 'try' and error propagation.
PVGame.swift [115-130]

Referred Code
let realm = try! Realm(configuration: .init(inMemoryIdentifier: "MockRealm"))
let systemIdentifier = systemID ?? "mock.system"

var games: [PVGame] = []
try! realm.write {
    for index in 1...count {
        let game = PVGame()
        game.title = "Mock Game \(index)"
        game.systemIdentifier = systemIdentifier
        game.md5Hash = UUID().uuidString // Mock MD5 hash
        game.publishDate = "\(1980 + index)"
        realm.add(game)
        games.append(game)
    }
}
return games
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Forced try usage: The code uses try! to create an in-memory Realm and to perform a write transaction without
handling potential initialization or write errors.

Referred Code
let realm = try! Realm(configuration: .init(inMemoryIdentifier: "MockRealm"))
let systemIdentifier = systemID ?? "mock.system"

var games: [PVGame] = []
try! realm.write {
    for index in 1...count {
        let game = PVGame()
        game.title = "Mock Game \(index)"
        game.systemIdentifier = systemIdentifier
        game.md5Hash = UUID().uuidString // Mock MD5 hash
        game.publishDate = "\(1980 + index)"
        realm.add(game)
        games.append(game)
    }
}
return games

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
No audit logs: The creation and persistence of mock games into Realm are not logged, which may omit audit
trails of write operations even in test/simulator contexts.

Referred Code
var games: [PVGame] = []
try! realm.write {
    for index in 1...count {
        let game = PVGame()
        game.title = "Mock Game \(index)"
        game.systemIdentifier = systemIdentifier
        game.md5Hash = UUID().uuidString // Mock MD5 hash
        game.publishDate = "\(1980 + index)"
        realm.add(game)
        games.append(game)
    }
}
return games

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Unvalidated inputs: The method writes mock data into Realm without validating external inputs like systemID or
count bounds, which could lead to issues if misused outside strictly test contexts.

Referred Code
public static func mockGenerate(systemID: String? = nil, count: Int = 10) -> [PVGame] {
    let realm = try! Realm(configuration: .init(inMemoryIdentifier: "MockRealm"))
    let systemIdentifier = systemID ?? "mock.system"

    var games: [PVGame] = []
    try! realm.write {
        for index in 1...count {
            let game = PVGame()
            game.title = "Mock Game \(index)"
            game.systemIdentifier = systemIdentifier
            game.md5Hash = UUID().uuidString // Mock MD5 hash
            game.publishDate = "\(1980 + index)"
            realm.add(game)
            games.append(game)
        }
    }
    return games
}

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Isolate in-memory Realm instances

The mockGenerate function uses a static inMemoryIdentifier, causing the same
Realm instance to be reused, which can lead to state leakage. Use a unique
identifier like UUID().uuidString for each call to ensure isolation.

Examples:

PVLibrary/Sources/PVRealm/RealmPlatform/Entities/PVGame.swift [115]
        let realm = try! Realm(configuration: .init(inMemoryIdentifier: "MockRealm"))

Solution Walkthrough:

Before:

public static func mockGenerate(systemID: String? = nil, count: Int = 10) -> [PVGame] {
    let realm = try! Realm(configuration: .init(inMemoryIdentifier: "MockRealm"))
    
    var games: [PVGame] = []
    try! realm.write {
        for index in 1...count {
            let game = PVGame()
            // ...
            realm.add(game)
            games.append(game)
        }
    }
    return games
}

After:

public static func mockGenerate(systemID: String? = nil, count: Int = 10) -> [PVGame] {
    let realm = try! Realm(configuration: .init(inMemoryIdentifier: UUID().uuidString))
    
    var games: [PVGame] = []
    try! realm.write {
        for index in 1...count {
            let game = PVGame()
            // ...
            realm.add(game)
            games.append(game)
        }
    }
    return games
}
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a significant design flaw where using a static inMemoryIdentifier can lead to state leakage in tests and previews, proposing a robust solution.

Medium
Possible issue
Use a unique in-memory identifier

To ensure test isolation, replace the hardcoded in-memory Realm identifier with
a unique one, such as UUID().uuidString, for each call to mockGenerate.

PVLibrary/Sources/PVRealm/RealmPlatform/Entities/PVGame.swift [115]

-let realm = try! Realm(configuration: .init(inMemoryIdentifier: "MockRealm"))
+let realm = try! Realm(configuration: .init(inMemoryIdentifier: UUID().uuidString))
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that a hardcoded Realm identifier can cause state pollution between tests, and proposing a unique ID for each call significantly improves test isolation and reliability.

Medium
Avoid force unwrapping with try!

Replace try! with a do-catch block to handle potential Realm errors gracefully
and prevent the application from crashing during mock data generation.

PVLibrary/Sources/PVRealm/RealmPlatform/Entities/PVGame.swift [115-130]

-let realm = try! Realm(configuration: .init(inMemoryIdentifier: "MockRealm"))
 let systemIdentifier = systemID ?? "mock.system"
+do {
+    let realm = try Realm(configuration: .init(inMemoryIdentifier: "MockRealm"))
+    var games: [PVGame] = []
+    try realm.write {
+        for index in 1...count {
+            let game = PVGame()
+            game.title = "Mock Game \(index)"
+            game.systemIdentifier = systemIdentifier
+            game.md5Hash = UUID().uuidString // Mock MD5 hash
+            game.publishDate = "\(1980 + index)"
+            realm.add(game)
+            games.append(game)
+        }
+    }
+    return games
+} catch {
+    print("Failed to generate mock games: \(error)")
+    return []
+}
 
-var games: [PVGame] = []
-try! realm.write {
-    for index in 1...count {
-        let game = PVGame()
-        game.title = "Mock Game \(index)"
-        game.systemIdentifier = systemIdentifier
-        game.md5Hash = UUID().uuidString // Mock MD5 hash
-        game.publishDate = "\(1980 + index)"
-        realm.add(game)
-        games.append(game)
-    }
-}
-return games
-
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why: The suggestion correctly points out the risk of crashing with try!, but its impact is moderate as this is a mock data generator where failing fast can be an acceptable design choice.

Low
  • More

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant