batch3_test.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. package fixture
  2. import (
  3. "database/sql"
  4. "testing"
  5. )
  6. // 本文件单测第三批(org 域)的纯映射规则:D1、status 值域翻译、bit(1)、NULL 列、哨兵时间。
  7. func TestLegacyStatusToTarget(t *testing.T) {
  8. if v, err := legacyStatusToTarget(1, "x"); err != nil || v != "active" {
  9. t.Errorf("1 应映射为 active,得到 %q / %v", v, err)
  10. }
  11. if v, err := legacyStatusToTarget(0, "x"); err != nil || v != "disabled" {
  12. t.Errorf("0 应映射为 disabled,得到 %q / %v", v, err)
  13. }
  14. // 1/0 之外必须报错,绝不默认 active(否则会把已停用的机构悄悄复活)
  15. for _, bad := range []int8{2, -1, 9} {
  16. if _, err := legacyStatusToTarget(bad, "x"); err == nil {
  17. t.Errorf("status=%d 应报错(拒绝猜测),实际通过", bad)
  18. }
  19. }
  20. }
  21. func TestMapInstitutionD1AndNulls(t *testing.T) {
  22. l := LegacySchool{
  23. ID: 63317, Name: "源思维",
  24. ProvinceID: 20, CityID: 218, DistrictID: 1869,
  25. GradePeriod: "1,2,3", Status: 1,
  26. }
  27. got, warns, err := MapInstitution(l)
  28. if err != nil {
  29. t.Fatalf("MapInstitution 出错:%v", err)
  30. }
  31. if got.InstitutionID != 63317 {
  32. t.Errorf("D1:institution_id 必须是 63317,实际 %d", got.InstitutionID)
  33. }
  34. if got.InstitutionName != "源思维" {
  35. t.Errorf("名称应原样,实际 %q", got.InstitutionName)
  36. }
  37. if got.Status != "active" {
  38. t.Errorf("status=1 → active,实际 %q", got.Status)
  39. }
  40. // legacy 无 code/address/phone 三列 → 必须 NULL,不编造
  41. if got.InstitutionCode.Valid || got.Address.Valid || got.Phone.Valid {
  42. t.Error("legacy 无 code/address/phone,必须落 NULL")
  43. }
  44. // 有省市区 id 时必须产生一条告警(提示 address 无法还原)
  45. if len(warns) == 0 {
  46. t.Error("有省市区 id 时应产生告警(target 无对应列)")
  47. }
  48. if !got.CreatedAt.Equal(orgEpoch()) || !got.UpdatedAt.Equal(orgEpoch()) {
  49. t.Error("legacy 无时间列,created_at/updated_at 应落 epoch 哨兵")
  50. }
  51. }
  52. func TestMapInstitutionRejectsEmptyName(t *testing.T) {
  53. if _, _, err := MapInstitution(LegacySchool{ID: 1, Name: "", Status: 1}); err == nil {
  54. t.Error("name 为空且目标列 NOT NULL 时应报错(不得填占位值),实际未报错")
  55. }
  56. }
  57. func TestMapCampusD1R17AndBit(t *testing.T) {
  58. // R17:campus 1 的 school_id=1,必须**如实保留**,不能"修正"成数据里常见的 63317
  59. l := LegacyCampus{ID: 1, Name: "城东校区", SchoolID: 1, Status: 1, SelfSupport: 0,
  60. Code: sql.NullString{String: "CD", Valid: true}}
  61. got, _, err := MapCampus(l)
  62. if err != nil {
  63. t.Fatalf("MapCampus 出错:%v", err)
  64. }
  65. if got.CampusID != 1 {
  66. t.Errorf("D1:campus_id 必须是 1,实际 %d", got.CampusID)
  67. }
  68. if got.InstitutionID != 1 {
  69. t.Errorf("R17:campus 1 的 institution_id 必须是 1,实际 %d", got.InstitutionID)
  70. }
  71. if got.SelfSupport != 0 {
  72. t.Errorf("bit(1)=0 应映射为 0,实际 %d", got.SelfSupport)
  73. }
  74. if got.CampusCode.String != "CD" {
  75. t.Errorf("code 应原样,实际 %q", got.CampusCode.String)
  76. }
  77. // bit(1)=1 → 1
  78. l2 := LegacyCampus{ID: 5, Name: "金湖校区", SchoolID: 63317, Status: 1, SelfSupport: 1}
  79. got2, _, err := MapCampus(l2)
  80. if err != nil {
  81. t.Fatalf("MapCampus 出错:%v", err)
  82. }
  83. if got2.SelfSupport != 1 {
  84. t.Errorf("bit(1)=1 应映射为 1,实际 %d", got2.SelfSupport)
  85. }
  86. // bit(1) 只应取 0/1
  87. bad := LegacyCampus{ID: 9, Name: "x", SchoolID: 1, Status: 1, SelfSupport: 48}
  88. if _, _, err := MapCampus(bad); err == nil {
  89. t.Error("self_support=48('0' 的 ASCII)应报错,不得当成 0/1")
  90. }
  91. }
  92. func TestMapCampusRejectsCampusZero(t *testing.T) {
  93. if _, _, err := MapCampus(LegacyCampus{ID: 0, Name: "x", SchoolID: 1, Status: 1}); err == nil {
  94. t.Error("campus_id=0 不应建行,应报错")
  95. }
  96. }
  97. func TestMapCampusRejectsOrphan(t *testing.T) {
  98. if _, _, err := MapCampus(LegacyCampus{ID: 9, Name: "x", SchoolID: 0, Status: 1}); err == nil {
  99. t.Error("school_id=0 会造出孤儿校区,应报错")
  100. }
  101. }
  102. func TestIsCrossOrgCampus(t *testing.T) {
  103. owner := map[int64]int64{1: 1, 2: 1, 5: 63317}
  104. // (63317, 1):校区 1 真实属于机构 1 → 跨机构
  105. if !IsCrossOrgCampus(63317, 1, owner) {
  106. t.Error("(63317,1) 应判为 cross-org-campus")
  107. }
  108. // (1, 1):一致
  109. if IsCrossOrgCampus(1, 1, owner) {
  110. t.Error("(1,1) 不应判为 cross-org-campus")
  111. }
  112. // campusid=0:机构级,永远不算跨机构
  113. if IsCrossOrgCampus(63317, 0, owner) {
  114. t.Error("campusid=0 不应判为 cross-org-campus")
  115. }
  116. // 未知校区:不判
  117. if IsCrossOrgCampus(63317, 999, owner) {
  118. t.Error("未知校区不应判为 cross-org-campus")
  119. }
  120. }