import 'package:drift/native.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:kooltap/database/app_database.dart'; /// The parts of the v12 schema that the v13 and v14 migrations touch. const _v12Schema = [ 'CREATE TABLE bar_tabs (id TEXT NOT NULL, customer_name TEXT NOT NULL, ' "status TEXT NOT NULL DEFAULT 'open', opened_at INTEGER NOT NULL, " 'closed_at INTEGER NULL, version INTEGER NOT NULL DEFAULT 0, ' 'PRIMARY KEY (id))', 'CREATE TABLE tab_items (id TEXT NOT NULL, tab_id TEXT NOT NULL, ' 'product_id TEXT NOT NULL, product_name TEXT NOT NULL, ' 'quantity INTEGER NOT NULL, unit_price_in_cents INTEGER NOT NULL, ' 'created_at INTEGER NOT NULL, PRIMARY KEY (id))', 'CREATE TABLE tab_item_purchases (id TEXT NOT NULL, ' 'tab_item_id TEXT NOT NULL, purchased_at INTEGER NOT NULL, ' 'removed_at INTEGER NULL, PRIMARY KEY (id))', 'CREATE TABLE products (id TEXT NOT NULL, name TEXT NOT NULL, ' 'category TEXT NOT NULL, stock_quantity INTEGER NOT NULL, ' 'low_stock_threshold INTEGER NOT NULL, price_in_cents INTEGER NOT NULL, ' 'image_path TEXT NULL, active INTEGER NOT NULL DEFAULT 1, ' 'PRIMARY KEY (id))', "INSERT INTO products VALUES ('prod-1', 'Beer', 'Drinks', 20, 5, 400, " 'NULL, 1)', "INSERT INTO bar_tabs VALUES ('tab-1', 'Alice', 'open', 1700000000, NULL, 4)", "INSERT INTO tab_items VALUES ('item-1', 'tab-1', 'prod-1', 'Beer', 3, 400, " '1700000100)', "INSERT INTO tab_item_purchases VALUES ('p-1', 'item-1', 1700000200, NULL)", "INSERT INTO tab_item_purchases VALUES ('p-2', 'item-1', 1700000300, " '1700000400)', "INSERT INTO tab_item_purchases VALUES ('orphan', 'gone', 1700000500, NULL)", 'PRAGMA user_version = 12', ]; void main() { late AppDatabase database; setUp(() { database = AppDatabase( NativeDatabase.memory( setup: (rawDatabase) { for (final statement in _v12Schema) { rawDatabase.execute(statement); } }, ), ); }); tearDown(() async { await database.close(); }); test('drops the unused status columns and keeps the tab', () async { final tabs = await database.select(database.barTabs).get(); expect(tabs.single.customerName, 'Alice'); expect(tabs.single.version, 4); final columns = await database .customSelect('PRAGMA table_info(bar_tabs)') .map((row) => row.read('name')) .get(); expect(columns, isNot(contains('status'))); expect(columns, isNot(contains('closed_at'))); }); test('backfills missing purchases up to the item quantity', () async { final purchases = await (database.select( database.tabItemPurchases, )..where((row) => row.tabItemId.equals('item-1'))).get(); final active = purchases.where((row) => row.removedAt == null); expect(active, hasLength(3)); expect(purchases.where((row) => row.removedAt != null), hasLength(1)); }); test('gives existing products a counted stock', () async { final product = await database.select(database.products).getSingle(); expect(product.infiniteStock, false); expect(product.stockQuantity, 20); }); test('deletes purchases whose item no longer exists', () async { final orphan = await (database.select( database.tabItemPurchases, )..where((row) => row.id.equals('orphan'))).getSingleOrNull(); expect(orphan, isNull); }); test('creates an empty tab event outbox', () async { expect(await database.select(database.tabEvents).get(), isEmpty); expect((await database.select(database.barTabs).get()), hasLength(1)); }); test('creates an empty stock adjustment outbox', () async { expect( await database.select(database.stockAdjustmentResults).get(), isEmpty, ); expect((await database.select(database.products).get()), hasLength(1)); }); test('gives products no server picture yet and an empty upload queue', () async { final product = await database.select(database.products).getSingle(); expect(product.imageId, isNull); expect(await database.select(database.pendingImageUploads).get(), isEmpty); }); }