diff --git a/packages/cloud_firestore/cloud_firestore/example/integration_test/instance_e2e.dart b/packages/cloud_firestore/cloud_firestore/example/integration_test/instance_e2e.dart index 108cd2565cfe..4d9e984a3657 100644 --- a/packages/cloud_firestore/cloud_firestore/example/integration_test/instance_e2e.dart +++ b/packages/cloud_firestore/cloud_firestore/example/integration_test/instance_e2e.dart @@ -187,6 +187,73 @@ void runInstanceTests() { skip: kIsWeb, ); + test( + 'Settings() - persistenceEnabled: false does not persist across terminate()', + () async { + // Regression test for https://github.com/firebase/flutterfire/issues/18659 + // Windows ignored persistenceEnabled: false (pointer-to-bool + never + // forwarded to the C++ SDK). Disk cache is the only state that + // survives terminate(); in-memory cache does not. + FirebaseFirestore firestoreFor( + String databaseId, { + required bool persistenceEnabled, + }) { + final firestore = FirebaseFirestore.instanceFor( + app: Firebase.app(), + databaseId: databaseId, + ); + firestore.settings = + Settings(persistenceEnabled: persistenceEnabled); + firestore.useFirestoreEmulator('localhost', 8080); + return firestore; + } + + Future writeThenTerminate(FirebaseFirestore firestore) async { + await firestore + .doc('flutter-tests/persistence-across-terminate') + .set({'foo': 'bar'}); + await firestore.waitForPendingWrites(); + await firestore.terminate(); + } + + const docPath = 'flutter-tests/persistence-across-terminate'; + const cacheGet = GetOptions(source: Source.cache); + + // Control: persistence on → cache must survive terminate. If this + // fails, Windows is not keeping a disk cache and the disabled case + // would not prove the setting was forwarded. + final enabled = firestoreFor( + 'persistence-enabled-18659', + persistenceEnabled: true, + ); + await writeThenTerminate(enabled); + + final cachedWhenEnabled = await enabled.doc(docPath).get(cacheGet); + expect(cachedWhenEnabled.data(), {'foo': 'bar'}); + expect(cachedWhenEnabled.metadata.isFromCache, isTrue); + await enabled.terminate(); + + final disabled = firestoreFor( + 'persistence-disabled-18659', + persistenceEnabled: false, + ); + await writeThenTerminate(disabled); + + await expectLater( + disabled.doc(docPath).get(cacheGet), + throwsA( + isA().having( + (e) => e.code, + 'code', + 'unavailable', + ), + ), + ); + await disabled.terminate(); + }, + skip: defaultTargetPlatform != TargetPlatform.windows, + ); + test( 'setIndexConfigurationFromJSON()', () async { diff --git a/packages/cloud_firestore/cloud_firestore/windows/cloud_firestore_plugin.cpp b/packages/cloud_firestore/cloud_firestore/windows/cloud_firestore_plugin.cpp index 9681f1390d7e..99a505060ae6 100644 --- a/packages/cloud_firestore/cloud_firestore/windows/cloud_firestore_plugin.cpp +++ b/packages/cloud_firestore/cloud_firestore/windows/cloud_firestore_plugin.cpp @@ -400,7 +400,10 @@ Firestore* GetFirestoreFromPigeon(const FirestorePigeonFirebaseApp& pigeonApp) { firebase::firestore::Settings settings; if (pigeonApp.settings().persistence_enabled()) { - bool persistEnabled = pigeonApp.settings().persistence_enabled(); + // The getter returns `const bool*` (null when unset); dereference to read + // the actual value rather than testing pointer presence. + bool persistEnabled = *pigeonApp.settings().persistence_enabled(); + settings.set_persistence_enabled(persistEnabled); // This is the maximum amount of cache allowed. We use the same number on // android.