package sqlite import ( "database/sql" "fmt" "path/filepath" "testing" ) // TestIsUniqueViolation checks the error recognition against a real SQLite, // because it turns on an extended result code the driver does not export as // a constant: a version bump that changed it would otherwise turn "that name // is taken" into a 500. func TestIsUniqueViolation(t *testing.T) { path := filepath.ToSlash(filepath.Join(t.TempDir(), "test.db")) db, err := sql.Open("sqlite", "file:"+path) if err != nil { t.Fatal(err) } t.Cleanup(func() { _ = db.Close() }) if _, err := db.ExecContext(t.Context(), `CREATE TABLE t (pk TEXT PRIMARY KEY, uniq TEXT UNIQUE)`); err != nil { t.Fatal(err) } insert := func(pk, uniq string) error { _, err := db.ExecContext(t.Context(), `INSERT INTO t (pk, uniq) VALUES (?, ?)`, pk, uniq) return err } if err := insert("a", "one"); err != nil { t.Fatal(err) } for name, err := range map[string]error{ "duplicate primary key": insert("a", "two"), "duplicate unique key": insert("b", "one"), } { t.Run(name, func(t *testing.T) { if err == nil { t.Fatal("the insert should have failed") } if !isUniqueViolation(err) { t.Errorf("isUniqueViolation(%v) = false, want true", err) } }) } // Something that is an error but not a constraint failure. _, err = db.ExecContext(t.Context(), `INSERT INTO nonexistent (x) VALUES (1)`) if err == nil { t.Fatal("inserting into a missing table should have failed") } if isUniqueViolation(err) { t.Errorf("isUniqueViolation(%v) = true, want false", err) } if isUniqueViolation(nil) || isUniqueViolation(fmt.Errorf("unrelated")) { t.Error("isUniqueViolation accepted something that is not a SQLite error") } }