mirror of
https://github.com/hanzoai/orm.git
synced 2026-10-30 15:01:22 +00:00
A host that embeds the engine beside its own log does not want a second one writing to stdout: Sync warns per column whenever a stored type or nullability disagrees with the struct, which is every open of a database some other mapper built. Silencing it needed the level type, which lived one import past the facade. Levels are named for what they mean rather than shouted, and the test measures the engine's output at Warn against its output at Silent.
103 lines
2.7 KiB
Go
103 lines
2.7 KiB
Go
package relational_test
|
|
|
|
import (
|
|
"database/sql"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/hanzoai/orm/relational"
|
|
_ "github.com/hanzoai/sqlite"
|
|
)
|
|
|
|
type row struct {
|
|
ID int64 `xorm:"'id' pk autoincr"`
|
|
Name string `xorm:"'name' notnull"`
|
|
}
|
|
|
|
func (row) TableName() string { return "rows" }
|
|
|
|
// TestBindSharesTheConnection proves Bind adopts the caller's handle rather
|
|
// than opening a second one: a row written through database/sql is visible to
|
|
// the engine, which is only true if both speak to the same pool.
|
|
func TestBindSharesTheConnection(t *testing.T) {
|
|
db, err := sql.Open("sqlite", t.TempDir()+"/bind.db")
|
|
if err != nil {
|
|
t.Fatalf("open: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
engine, err := relational.Bind("sqlite", "", db)
|
|
if err != nil {
|
|
t.Fatalf("bind: %v", err)
|
|
}
|
|
if err := engine.Sync(new(row)); err != nil {
|
|
t.Fatalf("sync: %v", err)
|
|
}
|
|
|
|
if _, err := db.Exec(`INSERT INTO rows (name) VALUES (?)`, "written outside"); err != nil {
|
|
t.Fatalf("insert: %v", err)
|
|
}
|
|
|
|
var got row
|
|
found, err := engine.Where("name = ?", "written outside").Get(&got)
|
|
if err != nil {
|
|
t.Fatalf("get: %v", err)
|
|
}
|
|
if !found {
|
|
t.Fatal("engine did not see the row written on the caller's handle")
|
|
}
|
|
}
|
|
|
|
// TestSilentEngineSaysNothing proves the levels reach the engine: an engine at
|
|
// Silent writes nothing where the same engine at Warn writes a line. The
|
|
// provocation is a column whose stored type disagrees with the struct, which is
|
|
// what Sync warns about, and what a host embedding this engine beside its own
|
|
// log does not want on stdout.
|
|
func TestSilentEngineSaysNothing(t *testing.T) {
|
|
say := func(level relational.LogLevel) string {
|
|
db, err := sql.Open("sqlite", t.TempDir()+"/level.db")
|
|
if err != nil {
|
|
t.Fatalf("open: %v", err)
|
|
}
|
|
defer db.Close()
|
|
if _, err := db.Exec(`CREATE TABLE rows (id INTEGER PRIMARY KEY AUTOINCREMENT, name INTEGER)`); err != nil {
|
|
t.Fatalf("create: %v", err)
|
|
}
|
|
|
|
saved := os.Stdout
|
|
r, w, err := os.Pipe()
|
|
if err != nil {
|
|
t.Fatalf("pipe: %v", err)
|
|
}
|
|
os.Stdout = w
|
|
engine, err := relational.Bind("sqlite", "", db)
|
|
os.Stdout = saved
|
|
if err != nil {
|
|
w.Close()
|
|
t.Fatalf("bind: %v", err)
|
|
}
|
|
engine.SetLogLevel(level)
|
|
|
|
done := make(chan string, 1)
|
|
go func() {
|
|
out, _ := io.ReadAll(r)
|
|
done <- string(out)
|
|
}()
|
|
if err := engine.Sync(new(row)); err != nil {
|
|
w.Close()
|
|
t.Fatalf("sync: %v", err)
|
|
}
|
|
w.Close()
|
|
return <-done
|
|
}
|
|
|
|
if out := say(relational.Warn); !strings.Contains(out, "name") {
|
|
t.Fatalf("at Warn the engine should have reported the column type disagreement, got %q", out)
|
|
}
|
|
if out := say(relational.Silent); out != "" {
|
|
t.Fatalf("at Silent the engine should say nothing, got %q", out)
|
|
}
|
|
}
|