package store import ( "database/sql" "errors" "path/filepath" "testing" "time" ) // OpenDB stellt Migrationsmechanik und Zeitformat auch anderen Datenbanken // bereit (z. B. accountant.db). func TestOpenDB_Migrations(t *testing.T) { path := filepath.Join(t.TempDir(), "x.db") v1 := []string{`CREATE TABLE a (id TEXT PRIMARY KEY, at DATETIME NOT NULL);`} db, err := OpenDB(ctx, path, v1) if err != nil { t.Fatal(err) } at := time.Date(2026, 10, 16, 8, 15, 30, 5, time.FixedZone("CEST", 2*3600)) if _, err := db.ExecContext(ctx, `INSERT INTO a VALUES ('x', ?)`, FormatTime(at)); err != nil { t.Fatal(err) } var got time.Time if err := db.QueryRowContext(ctx, `SELECT at FROM a`).Scan(ScanTime(&got)); err != nil { t.Fatal(err) } if !got.Equal(at) || got.Location() != time.UTC { t.Errorf("Zeit = %v, erwartet %v in UTC", got, at) } var null time.Time if err := db.QueryRowContext(ctx, `SELECT NULL`).Scan(ScanTime(&null)); err != nil || !null.IsZero() { t.Errorf("NULL = %v, %v", null, err) } db.Close() // Neue Migration wird angehängt, bestehende Daten bleiben. v2 := append(v1, `ALTER TABLE a ADD COLUMN note TEXT NOT NULL DEFAULT '';`) db, err = OpenDB(ctx, path, v2) if err != nil { t.Fatal(err) } var n int if err := db.QueryRowContext(ctx, `SELECT count(*) FROM a WHERE note = ''`).Scan(&n); err != nil || n != 1 { t.Errorf("nach Migration: n=%d err=%v", n, err) } db.Close() // Ältere Programmversion verweigert die neuere Datenbank. if _, err := OpenDB(ctx, path, v1); !errors.Is(err, ErrSchemaTooNew) { t.Errorf("ältere Version: %v, erwartet ErrSchemaTooNew", err) } } var _ sql.Scanner = ScanTime(nil)