github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/yaml/validate_test.go (about) 1 package yaml_test 2 3 import ( 4 "strings" 5 "testing" 6 7 "github.com/bingoohuang/gg/pkg/yaml" 8 "github.com/go-playground/validator/v10" 9 ) 10 11 func TestStructValidator(t *testing.T) { 12 type Inner struct { 13 Required string `validate:"required"` 14 Lt10 int `validate:"lt=10"` 15 } 16 cases := []struct { 17 TestName string 18 YAMLContent string 19 ExpectedErr string 20 Instance interface{} 21 }{ 22 { 23 TestName: "Test Simple Validation", 24 YAMLContent: `--- 25 - name: john 26 age: 20 27 - name: tom 28 age: -1 29 - name: ken 30 age: 10`, 31 ExpectedErr: `[5:8] Key: 'Age' Error:Field validation for 'Age' failed on the 'gte' tag 32 2 | - name: john 33 3 | age: 20 34 4 | - name: tom 35 > 5 | age: -1 36 ^ 37 6 | - name: ken 38 7 | age: 10`, 39 Instance: &[]struct { 40 Name string `yaml:"name" validate:"required"` 41 Age int `yaml:"age" validate:"gte=0,lt=120"` 42 }{}, 43 }, 44 { 45 TestName: "Test Missing Required Field", 46 YAMLContent: `--- 47 - name: john 48 age: 20 49 - age: 10`, 50 ExpectedErr: `[4:1] Key: 'Name' Error:Field validation for 'Name' failed on the 'required' tag 51 1 | --- 52 2 | - name: john 53 3 | age: 20 54 > 4 | - age: 10 55 ^ 56 `, 57 Instance: &[]struct { 58 Name string `yaml:"name" validate:"required"` 59 Age int `yaml:"age" validate:"gte=0,lt=120"` 60 }{}, 61 }, 62 { 63 TestName: "Test Nested Validation Missing Internal Required", 64 YAMLContent: `--- 65 name: john 66 age: 10 67 addr: 68 number: seven`, 69 ExpectedErr: `[4:5] Key: 'State' Error:Field validation for 'State' failed on the 'required' tag 70 1 | --- 71 2 | name: john 72 3 | age: 10 73 > 4 | addr: 74 ^ 75 5 | number: seven`, 76 Instance: &struct { 77 Name string `yaml:"name" validate:"required"` 78 Age int `yaml:"age" validate:"gte=0,lt=120"` 79 Addr struct { 80 Number string `yaml:"number" validate:"required"` 81 State string `yaml:"state" validate:"required"` 82 } `yaml:"addr"` 83 }{}, 84 }, 85 { 86 TestName: "Test nested Validation with unknown field", 87 YAMLContent: `--- 88 name: john 89 age: 20 90 addr: 91 number: seven 92 state: washington 93 error: error 94 `, 95 ExpectedErr: `[7:3] unknown field "error" 96 4 | addr: 97 5 | number: seven 98 6 | state: washington 99 > 7 | error: error 100 ^ 101 `, 102 Instance: &struct { 103 Name string `yaml:"name" validate:"required"` 104 Age int `yaml:"age" validate:"gte=0,lt=120"` 105 Addr *struct { 106 Number string `yaml:"number" validate:"required"` 107 State string `yaml:"state" validate:"required"` 108 } `yaml:"addr" validate:"required"` 109 }{}, 110 }, 111 { 112 TestName: "Test Validation with wrong field type", 113 YAMLContent: `--- 114 name: myDocument 115 roles: 116 name: myRole 117 permissions: 118 - hello 119 - how 120 - are 121 - you 122 `, 123 ExpectedErr: `[4:7] mapping was used where sequence is expected 124 1 | --- 125 2 | name: myDocument 126 3 | roles: 127 > 4 | name: myRole 128 ^ 129 5 | permissions: 130 6 | - hello 131 7 | - how 132 8 | `, 133 Instance: &struct { 134 Name string `yaml:"name"` 135 Roles []struct { 136 Name string `yaml:"name"` 137 Permissions []string `yaml:"permissions"` 138 } `yaml:"roles"` 139 }{}, 140 }, 141 { 142 TestName: "Test inline validation missing required", 143 YAMLContent: `--- 144 name: john 145 age: 20 146 `, 147 ExpectedErr: `Key: 'Inner.Required' Error:Field validation for 'Required' failed on the 'required' tag`, 148 Instance: &struct { 149 Name string `yaml:"name" validate:"required"` 150 Age int `yaml:"age" validate:"gte=0,lt=120"` 151 Inner `yaml:",inline"` 152 }{}, 153 }, 154 { 155 TestName: "Test inline validation field error", 156 YAMLContent: `--- 157 name: john 158 age: 20 159 required: present 160 lt10: 20 161 `, 162 ExpectedErr: `[5:7] Key: 'Inner.Lt10' Error:Field validation for 'Lt10' failed on the 'lt' tag 163 2 | name: john 164 3 | age: 20 165 4 | required: present 166 > 5 | lt10: 20 167 ^ 168 `, 169 Instance: &struct { 170 Name string `yaml:"name" validate:"required"` 171 Age int `yaml:"age" validate:"gte=0,lt=120"` 172 Inner `yaml:",inline"` 173 }{}, 174 }, 175 } 176 177 for _, tc := range cases { 178 tc := tc // NOTE: https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables 179 t.Run(tc.TestName, func(t *testing.T) { 180 validate := validator.New() 181 dec := yaml.NewDecoder( 182 strings.NewReader(tc.YAMLContent), 183 yaml.Validator(validate), 184 yaml.Strict(), 185 ) 186 err := dec.Decode(tc.Instance) 187 switch { 188 case tc.ExpectedErr != "" && err == nil: 189 t.Fatal("expected error") 190 case tc.ExpectedErr == "" && err != nil: 191 t.Fatalf("unexpected error: %v", err) 192 case tc.ExpectedErr != "" && tc.ExpectedErr != err.Error(): 193 t.Fatalf("expected `%s` but actual `%s`", tc.ExpectedErr, err.Error()) 194 } 195 }) 196 } 197 }