| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- package main
- import (
- "database/sql"
- "path/filepath"
- "testing"
- )
- // TestRecordServiceSQLite 验证记录 SQLite 存储:建表、插入、查询、去重、全量替换。
- // 直接测试 openRecordDB 返回的 *sql.DB(绕过 SettingsService 的 loadSettings 依赖)。
- func TestRecordServiceSQLite(t *testing.T) {
- dir := t.TempDir()
- dbPath := filepath.Join(dir, "records.db")
- // 未配置路径时应报错(openRecordDB 空路径)
- if _, err := openRecordDB(""); err == nil {
- t.Fatal("空数据库路径应返回错误")
- }
- // 打开(自动建表 + WAL)
- db, err := openRecordDB(dbPath)
- if err != nil {
- t.Fatalf("openRecordDB 失败: %v", err)
- }
- defer db.Close()
- // 插入 3 条
- for _, r := range []struct{ n, i string; v float64 }{
- {"张三", "一月", 12.5},
- {"张三", "二月", 30},
- {"李四", "一月", 8.2},
- } {
- if _, err := db.Exec(`INSERT INTO records (name, item, value) VALUES (?,?,?)`, r.n, r.i, r.v); err != nil {
- t.Fatalf("插入失败: %v", err)
- }
- }
- // 按 id 升序读取
- rows, err := db.Query(`SELECT name, item, value FROM records ORDER BY id ASC`)
- if err != nil {
- t.Fatalf("查询失败: %v", err)
- }
- var got []RecordItem
- for rows.Next() {
- var it RecordItem
- if err := rows.Scan(&it.Name, &it.Item, &it.Value); err != nil {
- t.Fatalf("扫描失败: %v", err)
- }
- got = append(got, it)
- }
- rows.Close()
- if len(got) != 3 {
- t.Fatalf("期望 3 条记录,实际 %d", len(got))
- }
- if got[0].Name != "张三" || got[0].Item != "一月" || got[0].Value != 12.5 {
- t.Fatalf("首条记录不符: %+v", got[0])
- }
- // 去重姓名(UTF-8 字节序:张三 < 李四)
- names := distinctTest(t, db, "name")
- if len(names) != 2 || names[0] != "张三" || names[1] != "李四" {
- t.Fatalf("去重姓名不符: %v", names)
- }
- // 去重名称(排序:一月、二月)
- items := distinctTest(t, db, "item")
- if len(items) != 2 || items[0] != "一月" || items[1] != "二月" {
- t.Fatalf("去重名称不符: %v", items)
- }
- // 非法列名应报错
- if _, err := recordDistinctValues("evil"); err == nil {
- t.Fatal("非法列名应返回错误")
- }
- // 全量替换:清空后写 1 条
- tx, err := db.Begin()
- if err != nil {
- t.Fatalf("开启事务失败: %v", err)
- }
- if _, err := tx.Exec(`DELETE FROM records`); err != nil {
- t.Fatalf("清空失败: %v", err)
- }
- stmt, err := tx.Prepare(`INSERT INTO records (name, item, value) VALUES (?,?,?)`)
- if err != nil {
- t.Fatalf("准备语句失败: %v", err)
- }
- if _, err := stmt.Exec("王五", "三月", 99); err != nil {
- t.Fatalf("替换插入失败: %v", err)
- }
- stmt.Close()
- if err := tx.Commit(); err != nil {
- t.Fatalf("提交失败: %v", err)
- }
- var cnt int
- if err := db.QueryRow(`SELECT COUNT(*) FROM records`).Scan(&cnt); err != nil || cnt != 1 {
- t.Fatalf("全量替换后应有 1 条,实际 %d (err=%v)", cnt, err)
- }
- }
- // distinctTest 对已打开 db 执行与 recordDistinctValues 相同的去重 SQL。
- func distinctTest(t *testing.T, db *sql.DB, col string) []string {
- t.Helper()
- rows, err := db.Query(`SELECT DISTINCT ` + col + ` FROM records WHERE TRIM(` + col + `) <> '' ORDER BY ` + col + ` COLLATE NOCASE ASC`)
- if err != nil {
- t.Fatalf("去重查询失败: %v", err)
- }
- defer rows.Close()
- var vals []string
- for rows.Next() {
- var v string
- if err := rows.Scan(&v); err != nil {
- t.Fatalf("扫描去重值失败: %v", err)
- }
- vals = append(vals, v)
- }
- return vals
- }
|