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  }