github.com/cloudwego/dynamicgo@v0.2.6-0.20240519101509-707f41b6b834/thrift/idl_test.go (about) 1 /** 2 * Copyright 2023 CloudWeGo Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package thrift 18 19 import ( 20 "context" 21 "fmt" 22 "math" 23 "testing" 24 25 "github.com/cloudwego/thriftgo/parser" 26 "github.com/stretchr/testify/require" 27 ) 28 29 func TestThriftContentWithAbsIncludePath(t *testing.T) { 30 path := "a/b/main.thrift" 31 content := ` 32 namespace go kitex.test.server 33 include "x.thrift" 34 include "../y.thrift" 35 36 service InboxService {} 37 ` 38 includes := map[string]string{ 39 path: content, 40 "a/b/x.thrift": "namespace go kitex.test.server", 41 "a/y.thrift": ` 42 namespace go kitex.test.server 43 include "z.thrift" 44 `, 45 "a/z.thrift": "namespace go kitex.test.server", 46 } 47 p, err := NewDescritorFromContent(context.Background(), path, content, includes, true) 48 if err != nil { 49 t.Fatal(err) 50 } 51 fmt.Printf("%#v\n", p) 52 } 53 54 func TestBitmap(t *testing.T) { 55 content := ` 56 namespace go kitex.test.server 57 struct Base { 58 1: string A 59 2: required string B 60 3: optional string C 61 32767: required string D 62 } 63 service InboxService { 64 Base ExampleMethod(1: Base req) 65 }` 66 p, err := GetDescFromContent(content, "ExampleMethod", &Options{}) 67 require.NoError(t, err) 68 testID := math.MaxInt16 69 println(testID/int64BitSize, testID%int64BitSize) 70 x := p.Request().Struct().FieldByKey("req").Type().Struct().Requires() 71 exp := []uint64{0x6} 72 for i := 0; i < int(testID)/int64BitSize-1; i++ { 73 exp = append(exp, 0) 74 } 75 exp = append(exp, 0x8000000000000000) 76 require.Equal(t, RequiresBitmap(exp), (x)) 77 } 78 79 func TestDynamicgoDeprecated(t *testing.T) { 80 path := "a/b/main.thrift" 81 content := ` 82 namespace go kitex.test.server 83 struct Base { 84 1: required string required_field 85 999: required string ignored (` + AnnoKeyDynamicGoDeprecated + `="") 86 3: string pass 87 } 88 89 service InboxService { 90 string ExampleMethod(1: Base req) 91 } 92 ` 93 includes := map[string]string{ 94 path: content, 95 } 96 p, err := NewDescritorFromContent(context.Background(), path, content, includes, true) 97 if err != nil { 98 t.Fatal(err) 99 } 100 fmt.Printf("%#v\n", p) 101 x := p.Functions()["ExampleMethod"].Request().Struct().FieldByKey("req").Type().Struct() 102 require.Equal(t, (*FieldDescriptor)(nil), x.FieldById(999)) 103 require.NotNil(t, x.FieldById(3)) 104 require.Equal(t, (*FieldDescriptor)(nil), x.FieldByKey("ignored")) 105 require.Equal(t, true, x.requires.IsSet(FieldID(1))) 106 require.Equal(t, true, x.requires.IsSet(FieldID(3))) 107 } 108 109 func TestHttpEndPoints(t *testing.T) { 110 p, err := NewDescritorFromPath(context.Background(), "../testdata/idl/example3.thrift") 111 if err != nil { 112 t.Fatal(err) 113 } 114 fmt.Printf("%#v\n", p) 115 ep1 := p.Functions()["ExampleMethod"].endpoints 116 require.Equal(t, 1, len(ep1)) 117 require.Equal(t, "POST", ep1[0].Method) 118 require.Equal(t, "/example/set", ep1[0].Path) 119 ep2 := p.Functions()["ErrorMethod"].endpoints 120 require.Equal(t, 1, len(ep2)) 121 require.Equal(t, "GET", ep2[0].Method) 122 require.Equal(t, "/example/get", ep2[0].Path) 123 } 124 125 func TestBypassAnnotatio(t *testing.T) { 126 path := "a/b/main.thrift" 127 content := ` 128 namespace go kitex.test.server 129 130 service InboxService { 131 string ExampleMethod(1: string req) (anno1 = "", anno.test = "中文1", anno.test = "中文2") 132 } (anno1 = "", anno.test = "中文1", anno.test = "中文2") 133 ` 134 135 includes := map[string]string{ 136 path: content, 137 } 138 p, err := NewDescritorFromContent(context.Background(), path, content, includes, true) 139 if err != nil { 140 t.Fatal(err) 141 } 142 require.Equal(t, []parser.Annotation{{Key: "anno1", Values: []string{""}}, {Key: "anno.test", Values: []string{"中文1", "中文2"}}}, p.Annotations()) 143 require.Equal(t, []parser.Annotation{{Key: "anno1", Values: []string{""}}, {Key: "anno.test", Values: []string{"中文1", "中文2"}}}, p.Functions()["ExampleMethod"].Annotations()) 144 } 145 146 func GetDescFromContent(content string, method string, opts *Options) (*FunctionDescriptor, error) { 147 path := "a/b/main.thrift" 148 includes := map[string]string{ 149 path: content, 150 } 151 p, err := opts.NewDescritorFromContent(context.Background(), path, content, includes, true) 152 if err != nil { 153 return nil, err 154 } 155 return p.Functions()[method], nil 156 } 157 158 // func TestRequireBitmap(t *testing.T) { 159 // reqs := NewRequiresBitmap() 160 // reqs.Set(256, DefaultRequireness) 161 // b := (*reqs)[:5] 162 // require.Equal(t, b[4], uint64(0x1)) 163 // FreeRequiresBitmap(reqs) 164 // reqs2 := NewRequiresBitmap() 165 // if cap(*reqs2) >= 5 { 166 // b := (*reqs2)[:5] 167 // require.Equal(t, b[4], uint64(0x1)) 168 // } 169 // } 170 171 func TestDefalutValue(t *testing.T) { 172 t.Run("use", func(t *testing.T) { 173 p, err := Options{ 174 UseDefaultValue: true, 175 }.NewDescritorFromPath(context.Background(), "../testdata/idl/example.thrift") 176 require.NoError(t, err) 177 desc := p.Functions()["ExampleDefaultValue"].Request().Struct().Fields()[0].Type() 178 buf := make([]byte, 11) 179 BinaryEncoding{}.EncodeString(buf, "default") 180 dv := &DefaultValue{ 181 goValue: "default", 182 jsonValue: `"default"`, 183 thriftBinary: string(buf), 184 } 185 require.Equal(t, dv, desc.Struct().FieldById(1).DefaultValue()) 186 buf = make([]byte, 4) 187 BinaryEncoding{}.EncodeInt32(buf, int32(1)) 188 dv = &DefaultValue{ 189 goValue: int64(1), 190 jsonValue: `1`, 191 thriftBinary: string(buf), 192 } 193 require.Equal(t, dv, desc.Struct().FieldById(2).DefaultValue()) 194 buf = make([]byte, 8) 195 BinaryEncoding{}.EncodeDouble(buf, float64(1.1)) 196 dv = &DefaultValue{ 197 goValue: float64(1.1), 198 jsonValue: `1.1`, 199 thriftBinary: string(buf), 200 } 201 require.Equal(t, dv, desc.Struct().FieldById(3).DefaultValue()) 202 dv = &DefaultValue{ 203 goValue: true, 204 jsonValue: `true`, 205 thriftBinary: string([]byte{1}), 206 } 207 require.Equal(t, dv, desc.Struct().FieldById(4).DefaultValue()) 208 require.Equal(t, (*DefaultValue)(nil), desc.Struct().FieldById(5).DefaultValue()) 209 require.Equal(t, (*DefaultValue)(nil), desc.Struct().FieldById(6).DefaultValue()) 210 require.Equal(t, (*DefaultValue)(nil), desc.Struct().FieldById(7).DefaultValue()) 211 buf = make([]byte, 16) 212 BinaryEncoding{}.EncodeString(buf, "const string") 213 dv = &DefaultValue{ 214 goValue: "const string", 215 jsonValue: `"const string"`, 216 thriftBinary: string(buf), 217 } 218 require.Equal(t, dv, desc.Struct().FieldById(8).DefaultValue()) 219 buf = make([]byte, 4) 220 BinaryEncoding{}.EncodeInt32(buf, int32(1)) 221 dv = &DefaultValue{ 222 goValue: int64(1), 223 jsonValue: `1`, 224 thriftBinary: string(buf), 225 } 226 require.Equal(t, dv, desc.Struct().FieldById(9).DefaultValue()) 227 }) 228 t.Run("not use", func(t *testing.T) { 229 p, err := Options{ 230 UseDefaultValue: false, 231 }.NewDescritorFromPath(context.Background(), "../testdata/idl/example.thrift") 232 require.NoError(t, err) 233 desc := p.Functions()["ExampleDefaultValue"].Request().Struct().Fields()[0].Type() 234 require.Equal(t, (*DefaultValue)(nil), desc.Struct().FieldById(1).DefaultValue()) 235 require.Equal(t, (*DefaultValue)(nil), desc.Struct().FieldById(2).DefaultValue()) 236 require.Equal(t, (*DefaultValue)(nil), desc.Struct().FieldById(3).DefaultValue()) 237 require.Equal(t, (*DefaultValue)(nil), desc.Struct().FieldById(4).DefaultValue()) 238 require.Equal(t, (*DefaultValue)(nil), desc.Struct().FieldById(5).DefaultValue()) 239 require.Equal(t, (*DefaultValue)(nil), desc.Struct().FieldById(6).DefaultValue()) 240 require.Equal(t, (*DefaultValue)(nil), desc.Struct().FieldById(7).DefaultValue()) 241 require.Equal(t, (*DefaultValue)(nil), desc.Struct().FieldById(8).DefaultValue()) 242 require.Equal(t, (*DefaultValue)(nil), desc.Struct().FieldById(9).DefaultValue()) 243 }) 244 } 245 246 func TestOptionSetOptionalBitmap(t *testing.T) { 247 content := ` 248 namespace go kitex.test.server 249 250 struct Base { 251 1: string DefaultField, 252 2: optional string OptionalField, 253 3: required string RequiredField, 254 } 255 256 service InboxService { 257 Base ExampleMethod(1: Base req) 258 } 259 ` 260 p, err := GetDescFromContent(content, "ExampleMethod", &Options{ 261 SetOptionalBitmap: true, 262 }) 263 require.NoError(t, err) 264 req := p.Request().Struct().Fields()[0].Type() 265 266 require.Equal(t, DefaultRequireness, req.Struct().FieldById(1).Required()) 267 require.Equal(t, OptionalRequireness, req.Struct().FieldById(2).Required()) 268 require.Equal(t, RequiredRequireness, req.Struct().FieldById(3).Required()) 269 require.Equal(t, true, req.Struct().Requires().IsSet(1)) 270 require.Equal(t, true, req.Struct().Requires().IsSet(2)) 271 require.Equal(t, true, req.Struct().Requires().IsSet(3)) 272 } 273 274 func TestOptionPutNameSpaceToAnnotation(t *testing.T) { 275 content := ` 276 namespace py py.base 277 namespace go go.base 278 279 struct Base { 280 1: string DefaultField, 281 2: optional string OptionalField, 282 3: required string RequiredField, 283 } 284 285 service InboxService { 286 Base ExampleMethod(1: Base req) 287 } 288 ` 289 p, err := GetDescFromContent(content, "ExampleMethod", &Options{ 290 PutNameSpaceToAnnotation: true, 291 }) 292 require.NoError(t, err) 293 req := p.Request().Struct().Fields()[0].Type() 294 annos := req.Struct().Annotations() 295 var ns *parser.Annotation 296 for i, a := range annos { 297 if a.Key == NameSpaceAnnotationKey { 298 ns = &annos[i] 299 break 300 } 301 } 302 require.NotNil(t, ns) 303 require.Equal(t, ns.Values, []string{"py", "py.base", "go", "go.base"}) 304 } 305 306 func TestNewFunctionDescriptorFromContent_absPath(t *testing.T) { 307 content := ` 308 include "/a/b/main.thrift" 309 include "/ref.thrift" 310 311 namespace go kitex.test.server 312 313 struct Base { 314 1: string DefaultField = ref.ConstString, 315 2: optional string OptionalField, 316 3: required string RequiredField, 317 } 318 319 service InboxService { 320 Base Method1(1: Base req) 321 Base Method2(1: Base req) 322 } 323 ` 324 ref := ` 325 include "/a/b/main.thrift" 326 327 namespace go ref 328 329 const string ConstString = "const string" 330 ` 331 path := "/a/b/main.thrift" 332 includes := map[string]string{ 333 path: content, 334 "/ref.thrift": ref, 335 } 336 337 p, err := Options{}.NewDescriptorFromContentWithMethod(context.Background(), path, content, includes, false, "Method1") 338 require.NoError(t, err) 339 require.NotNil(t, p.Functions()["Method1"]) 340 require.Nil(t, p.Functions()["Method2"]) 341 } 342 343 func TestNewFunctionDescriptorFromContent_relativePath(t *testing.T) { 344 content := ` 345 include "main.thrift" 346 include "ref.thrift" 347 348 namespace go kitex.test.server 349 350 struct Base { 351 1: string DefaultField = ref.ConstString, 352 2: optional string OptionalField, 353 3: required string RequiredField, 354 } 355 356 service InboxService { 357 Base Method1(1: Base req) 358 Base Method2(1: Base req) 359 } 360 ` 361 ref := ` 362 include "/a/b/main.thrift" 363 364 namespace go ref 365 366 const string ConstString = "const string" 367 ` 368 path := "/a/b/main.thrift" 369 includes := map[string]string{ 370 path: content, 371 "/a/b/ref.thrift": ref, 372 } 373 p, err := Options{}.NewDescriptorFromContentWithMethod(context.Background(), path, content, includes, true, "Method1") 374 require.NoError(t, err) 375 require.NotNil(t, p.Functions()["Method1"]) 376 require.Nil(t, p.Functions()["Method2"]) 377 } 378 379 func TestNewFunctionDescriptorFromPath(t *testing.T) { 380 p, err := Options{}.NewDescriptorFromPathWithMethod(context.Background(), "../testdata/idl/example.thrift", nil, "ExampleMethod") 381 require.NoError(t, err) 382 require.NotNil(t, p.Functions()["ExampleMethod"]) 383 require.Nil(t, p.Functions()["Ping"]) 384 }