Skip to main content

sembast-test-setup

Use when validating a sembast DatabaseFactory implementation (io, web, sqflite, idb, a custom jdb backend) against the shared sembast conformance suites of package:sembast_test: DatabaseTestContext, DatabaseTestContextJdb, DatabaseTestContextFs, DatabaseTestContextIo, memoryDatabaseContext, databaseTestContextJdbMemory, memoryFsDatabaseContext, databaseContextIo, createDatabaseContextIo, all_test.dart defineTests, all_jdb_test.dart defineJdbTests, all_fs_test.dart, allIoGroup, setupForTest, deleteForTest, dbPathFromName, reOpen, hasStorage, getExistingDatabaseVersion, and the demonstration codecs getEncryptSembastCodec, EncryptedDatabaseFactory, SembastBase64Codec, MyJsonCodec.

معلومات المصدر

المستودع
tekartik/sembast.dart
آخر نشاط في المصدر
٢٠ سبتمبر ٢٠٢٦ في ٢٠:٤٥
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٨٦٦
التفرعات
٧١

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
sembast-test-setup
description
Use when validating a sembast DatabaseFactory implementation (io, web, sqflite, idb, a custom jdb backend) against the shared sembast conformance suites of package:sembast_test: DatabaseTestContext, DatabaseTestContextJdb, DatabaseTestContextFs, DatabaseTestContextIo, memoryDatabaseContext, databaseTestContextJdbMemory, memoryFsDatabaseContext, databaseContextIo, createDatabaseContextIo, all_test.dart defineTests, all_jdb_test.dart defineJdbTests, all_fs_test.dart, allIoGroup, setupForTest, deleteForTest, dbPathFromName, reOpen, hasStorage, getExistingDatabaseVersion, and the demonstration codecs getEncryptSembastCodec, EncryptedDatabaseFactory, SembastBase64Codec, MyJsonCodec.
# sembast_test: the shared sembast conformance test suites `package:sembast_test` holds the test suites `sembast` itself runs, packaged as `defineTests(context)` functions instead of `main()`. Any package that provides a sembast `DatabaseFactory` (`sembast_web`, `sembast_sqflite`, an `idb_shim` journal backend, your own storage) wires its factory into a `DatabaseTestContext` and gets the whole CRUD / query / transaction / listener / codec / import-export suite for free. ## Guidelines ### Depending on it * Not on pub.dev (`publish_to: none`). Add it as a **dev dependency**, from git: ```yaml dev_dependencies: sembast_test: git: url: https://github.com/tekartik/sembast.dart path: sembast_test test: ``` The README still shows `ref: dart2_3`; that is a legacy branch. Real consumers (`sembast_sqflite_common_test`, `tekartik_sembast_flutter`) depend on the default branch with no `ref:`. * It is a test-only package: never import it from `lib/` of a shipped package. The one exception is a `*_test` helper package that re-exports contexts for its own consumers (see `sembast_sqflite_common_test`). ### Imports * `package:sembast_test/test_common.dart` is the single import for a suite file: it declares `DatabaseTestContext` and re-exports `package:test/test.dart` (`group`, `test`, `expect`, `setUp`…), the sembast v2 API (`Database`, `DatabaseFactory`, `StoreRef`, `Finder`, `Filter`, `SembastCodec`…) and the helpers of `src/test_defs.dart`. You normally do not need to import `package:test/test.dart` or `package:sembast/sembast.dart` next to it. * Suite entry points, each in its own library, imported **with a prefix** because several of them declare `defineTests`: * `package:sembast_test/all_test.dart` → `defineTests(DatabaseTestContext)` — the main suite (crud, database, store, record, find, transaction, key, listener, open, exception, value, query, sort, doc, codec, import/export, records, persistent change listeners). * `package:sembast_test/all_jdb_test.dart` → `defineJdbTests(DatabaseTestContextJdb)` — journal-database backends (format, codec, concurrency). Needs a factory implementing `DatabaseFactoryJdb`. * `package:sembast_test/all_fs_test.dart` → `defineTests(DatabaseTestContextFs)` — on-disk file format and codec. Needs a factory implementing `DatabaseFactoryFs`. * `package:sembast_test/all_io_test.dart` → `allIoGroup(DatabaseTestContextIo)` — `dart:io` import/export, VM only. * Single suites are importable one by one (`crud_test.dart`, `find_test.dart`, `query_test.dart`, `transaction_test.dart`, `listener_test.dart`, `open_test.dart`, `codec_test.dart`, `database_import_export_test.dart`…), each exposing `defineTests(ctx)` (a few use a longer name: `defineRecordTests`, `defineQueryTests`, `defineDatabaseClientTests`, `defineJdbDatabaseFormatTests`, `defineJdbConcurrentDatabaseTests`). Use them to bisect a failure, not as the normal entry point. ### Contexts * `DatabaseTestContext` has one mutable field, `factory`, plus `deleteAndOpen(path, {version, codec})` and `open(path, {version, codec})`. Build one with `DatabaseTestContext()..factory = myFactory`. * Ready-made contexts: `memoryDatabaseContext` (`test_common.dart`), `databaseTestContextJdbMemory` (`jdb_test_common.dart`), `memoryFsDatabaseContext` (`fs_test_common.dart`), `databaseContextIo` and `createDatabaseContextIo({rootPath})` (`io_test_common.dart`, VM only), `memoryFileSystemContext` / `fileSystemContextIo` / `createFileSystemContextIo({rootPath})` for the `FileSystemTestContext` based format tests. * Subclasses expose the backend object: `DatabaseTestContextJdb.jdbFactory`, `DatabaseTestContextFs.fs`. They cast `factory`, so give them a factory of the matching kind or the getter throws. * A context is stateful only through `factory`; one context can be shared by several `define*Tests` calls in the same `main()`, as the sembast tests do. ### Helpers (from `test_common.dart`) * `setupForTest(ctx, name, {codec})` deletes and opens a database at `dbPathFromName(name)` = `.dart_tool/sembast/test/<name>`; `deleteForTest(ctx, name)` only deletes and returns that path. Always go through them so runs are reproducible and paths stay inside `.dart_tool`. * `reOpen(db, {mode})` closes and reopens the same database with the same codec — the standard way to assert that data survived a restart. * `hasStorage(factory)` is false for the pure memory factory; `hasStorageJdb( factory)` is true for a `DatabaseFactoryJdb`. Guard persistence assertions with them so one suite can run on memory and on disk. * `getExistingDatabaseVersion(factory, path)` opens with `DatabaseMode.existing`, reads `version`, closes. * `isRunningAsJavascript` / `isJavascriptVm` / `kSembastDartIsWeb` skip VM-only expectations in a browser run; `TestException` is a throwaway exception; `readContent` / `writeContent` read and write a sembast `FileSystem` as lines; `devPrintJson(map)` pretty-prints. * `package:sembast_test/fs_test_common.dart` adds `fsExportToStringList`, `fsExportToMapList` and `fsImportFromMapList` to inspect or forge the on-disk JSON-lines format; `package:sembast_test/jdb_test_common.dart` adds `jdbImportFromMap` and `jdbDatabaseImportFromMap` to preload a journal database. * `package:sembast_test/test_common_impl.dart` exposes `getDatabaseExportStat(db)` (line/obsolete-line counts) for compaction tests. ### Codec helpers * `package:sembast_test/encrypt_codec.dart`: `getEncryptSembastCodec(password: ...)` returns a `SembastCodec` with signature `encrypt` (Salsa20 from `pointycastle`, md5-derived key, random 8-byte IV), and `EncryptedDatabaseFactory(databaseFactory: ..., password: ...)` wraps any factory so every `openDatabase` uses that codec (passing `codec:` to it asserts). The source says it explicitly: demonstration only, unauthenticated, weak key derivation — copy it as a starting point, do not ship it. * `package:sembast_test/base64_codec.dart`: `SembastBase64Codec` and `SembastBase64CodecAsync` (an `AsyncContentCodecBase`) — obfuscation, not encryption, and the async one is the template for a codec calling a plugin. * `package:sembast_test/test_codecs.dart`: `MyJsonCodec`, `MyCustomCodec`, `MyCustomRandomCodec` (adds a random seed, so two encodings of the same value differ), `MyJsonCodecDecoderThrow`, `MyJsonCodecEncoderThrow` — fixture codecs for error paths. ### Running and troubleshooting * `dart test` for a VM factory, `dart test -p chrome` for a web factory (`build_test` / `build_web_compilers` are needed in the consumer for browser runs). A test file targeting the VM starts with `@TestOn('vm')` + `library;`. * The suites are strict: they assume auto-incremented `int` keys per store, `String` keys, `Timestamp`/`Blob` support, transactions, `onSnapshot` listeners and `deleteDatabase`/`databaseExists`. A partial factory fails loudly; run `all_test.dart` first and only add `all_jdb_test.dart` / `all_fs_test.dart` when the corresponding interface is really implemented. * Several suites use `implementation_imports` of `package:sembast` (`src/api/v2/...`, `src/database_impl.dart`). That is deliberate for this package; do not copy the pattern into application code. * Expect the suites to create files under `.dart_tool/sembast/test/`; clean that directory when a format test misbehaves. ## Examples ### Full suite against your own factory ```dart @TestOn('vm') library; import 'package:sembast/sembast_io.dart'; import 'package:sembast_test/all_test.dart' as all_test; import 'package:sembast_test/test_common.dart'; void main() { // Any DatabaseFactory: databaseFactoryIo, databaseFactoryWeb, // getDatabaseFactorySqflite(...), your own implementation. var ctx = DatabaseTestContext()..factory = databaseFactoryIo; group('my_factory', () { all_test.defineTests(ctx); }); } ``` ### Journal (jdb) backend: main suite plus the jdb suite ```dart @TestOn('vm') library; import 'package:idb_shim/idb_io.dart'; import 'package:idb_shim/idb_jdb.dart'; import 'package:sembast_test/all_jdb_test.dart' as all_jdb_test; import 'package:sembast_test/all_test.dart' as all_test; import 'package:sembast_test/jdb_test_common.dart'; import 'package:sembast_test/test_common.dart'; Future<void> main() async { var jdbFactory = JdbFactoryIdb( getIdbFactorySembastIo('.dart_tool/sembast_test/idb'), ); // DatabaseTestContextJdb exposes ctx.jdbFactory to the jdb suite. var ctx = DatabaseTestContextJdb()..factory = DatabaseFactoryJdb(jdbFactory); group('idb_io', () { all_test.defineTests(ctx); all_jdb_test.defineJdbTests(ctx); }); } ``` ### File-system backend: main, fs and io suites ```dart @TestOn('vm') library; import 'package:sembast_test/all_fs_test.dart' as all_fs_test; import 'package:sembast_test/all_io_test.dart'; import 'package:sembast_test/all_test.dart' as all_test; import 'package:sembast_test/io_test_common.dart'; import 'package:test/test.dart'; void main() { // rootPath keeps every database of this run in one sandbox directory. var ctx = createDatabaseContextIo(rootPath: '.dart_tool/sembast_test/io'); all_test.defineTests(ctx); all_fs_test.defineTests(ctx); // on-disk format and codec allIoGroup(ctx); // dart:io import/export } ``` ### Own test using the context helpers ```dart import 'package:sembast/sembast_memory.dart'; import 'package:sembast_test/test_common.dart'; void main() { var ctx = DatabaseTestContext()..factory = newDatabaseFactoryMemory(); var record = StoreRef<String, Object?>.main().record('key'); test('value survives a reopen', () async { // Deletes then opens .dart_tool/sembast/test/my_app/basic.db var db = await setupForTest(ctx, 'my_app/basic.db'); await record.put(db, 'value'); db = await reOpen(db); // Memory factories have no storage: skip the persistence expectation. if (hasStorage(ctx.factory)) { expect(await record.get(db), 'value'); } await db.close(); }); } ``` ### Encrypted database with the demonstration codec ```dart import 'package:sembast/sembast_memory.dart'; import 'package:sembast_test/encrypt_codec.dart'; import 'package:sembast_test/test_common.dart'; void main() { var store = StoreRef<int, String>.main(); test('encrypt codec', () async { var factory = newDatabaseFactoryMemory(); // Demonstration cipher only; do not ship it as is. var codec = getEncryptSembastCodec(password: 'user_password'); var db = await factory.openDatabase('encrypted.db', codec: codec); await store.add(db, 'secret'); expect(await store.record(1).get(db), 'secret'); await db.close(); }); test('factory wrapper applies the codec to every open', () async { var factory = EncryptedDatabaseFactory( databaseFactory: newDatabaseFactoryMemory(), password: 'user_password', ); // Do not pass codec: here, the wrapper asserts it is null. var db = await factory.openDatabase('wrapped.db'); await store.add(db, 'secret'); await db.close(); }); } ``` ### A `*_test` helper package for your own backend ```dart import 'package:sembast/sembast_memory.dart'; import 'package:sembast_test/all_test.dart' as all_test; import 'package:sembast_test/test_common.dart'; /// Context published by your own `my_backend_test` package. class MyBackendTestContext extends DatabaseTestContext { MyBackendTestContext() { factory = newDatabaseFactoryMemory(); // your factory here } } /// Consumers call this from a single test file. void defineMyBackendTests(MyBackendTestContext ctx) { all_test.defineTests(ctx); test('backend specific behavior', () async { var db = await setupForTest(ctx, 'my_backend/extra.db'); expect(db.version, 1); await db.close(); }); } ``` ## Common mistakes * Importing two `all_*_test.dart` libraries without a prefix: `defineTests` is declared by several of them. * Passing a plain `DatabaseTestContext` to `defineJdbTests` / the fs suite, or a non-jdb factory to `DatabaseTestContextJdb`: the getter cast throws. * Adding `sembast_test` to `dependencies` instead of `dev_dependencies`. * Hard-coding database paths instead of `setupForTest` / `dbPathFromName`, which leaves files outside `.dart_tool` and breaks reruns. * Asserting persistence on `databaseFactoryMemory` (use `hasStorage`) or running `all_io_test.dart` in a browser (`@TestOn('vm')` only). * Shipping `getEncryptSembastCodec` / `EncryptedDatabaseFactory` in an app: it is an unauthenticated demonstration cipher.
عرض على GitHub