model_unexported_field_test.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. package DB
  2. import (
  3. "path/filepath"
  4. "strings"
  5. "testing"
  6. )
  7. // TestUseTableRejectsUnexportedField 回归测试: 含未导出字段的模型必须在建模阶段
  8. // (UseTable → ParseModel) 就返回带字段名的明确错误 —— 而不是拖到首次 Insert 才在
  9. // structToFieldValues 里对 reflect 拒绝访问的未导出字段 panic。
  10. // 被拒时库里不应留下半成品表。
  11. func TestUseTableRejectsUnexportedField(t *testing.T) {
  12. type badRow struct {
  13. BaseModel
  14. Name string
  15. age int // 未导出: reflect 无法读写, 旧实现到首次写入才 panic
  16. }
  17. db, err := Open(filepath.Join(t.TempDir(), "model_unexported.db"))
  18. if err != nil {
  19. t.Fatalf("打开: %v", err)
  20. }
  21. defer func() { _ = db.Close() }()
  22. tbl, err := UseTable[badRow](db, "badunexp")
  23. if err == nil {
  24. t.Fatalf("UseTable 应拒绝未导出字段, 却建表成功: %+v", tbl)
  25. }
  26. if !strings.Contains(err.Error(), "age") {
  27. t.Fatalf("错误应包含字段名 age, 得到: %v", err)
  28. }
  29. if _, ok := db.CoreDB().FindTable("badunexp"); ok {
  30. t.Fatal("被拒的模型不应在库里留下表")
  31. }
  32. // ParseModel 直调同样报错 (UseTable 之外的建模入口)
  33. if _, err := ParseModel(&badRow{}); err == nil {
  34. t.Fatal("ParseModel 应拒绝未导出字段")
  35. } else if !strings.Contains(err.Error(), "age") {
  36. t.Fatalf("ParseModel 错误应包含字段名 age, 得到: %v", err)
  37. }
  38. }
  39. // TestUseTableAcceptsEmbeddedBase 对照: 常见嵌入写法 (内嵌 DB.BaseModel,
  40. // 以及内嵌一个导出字段的普通结构体) 不受影响, 建模照常成功。
  41. func TestUseTableAcceptsEmbeddedBase(t *testing.T) {
  42. type auditFields struct {
  43. CreatedBy string `vrtx:"maxlen:32"`
  44. }
  45. type goodRow struct {
  46. BaseModel
  47. auditFields // 匿名嵌入: 递归展开, 不是未导出普通字段
  48. Name string
  49. }
  50. db, err := Open(filepath.Join(t.TempDir(), "model_embedded.db"))
  51. if err != nil {
  52. t.Fatalf("打开: %v", err)
  53. }
  54. defer func() { _ = db.Close() }()
  55. tbl, err := UseTable[goodRow](db, "goodembed")
  56. if err != nil {
  57. t.Fatalf("内嵌写法应建模成功: %v", err)
  58. }
  59. obj := &goodRow{Name: "x", auditFields: auditFields{CreatedBy: "u1"}}
  60. if err := tbl.Insert(obj); err != nil {
  61. t.Fatalf("Insert: %v", err)
  62. }
  63. got, err := tbl.Find(obj.ID)
  64. if err != nil {
  65. t.Fatalf("Find: %v", err)
  66. }
  67. if got.CreatedBy != "u1" || got.Name != "x" {
  68. t.Fatalf("嵌入字段读写异常: %+v", got)
  69. }
  70. }