github.com/kamalshkeir/kencoding@v0.0.2-0.20230409043843-44b609a0475a/proto/rewrite_test.go (about)

     1  package proto
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  )
     7  
     8  func TestRewrite(t *testing.T) {
     9  	type message struct {
    10  		A int
    11  		B float32
    12  		C float64
    13  		D string
    14  		M *message
    15  	}
    16  
    17  	tests := []struct {
    18  		scenario string
    19  		in       message
    20  		out      message
    21  		rw       Rewriter
    22  	}{
    23  		{
    24  			scenario: "identity",
    25  			in:       message{A: 42, M: &message{A: 1}},
    26  			out:      message{A: 42, M: &message{A: 1}},
    27  			rw:       MessageRewriter(nil),
    28  		},
    29  
    30  		{
    31  			scenario: "rewrite field 1",
    32  			in:       message{A: 21},
    33  			out:      message{A: 42},
    34  			rw: MessageRewriter{
    35  				1: FieldNumber(1).Int(42),
    36  			},
    37  		},
    38  
    39  		{
    40  			scenario: "rewrite field 2",
    41  			in:       message{A: 21, B: 0.125},
    42  			out:      message{A: 21, B: -1},
    43  			rw: MessageRewriter{
    44  				2: FieldNumber(2).Float32(-1),
    45  			},
    46  		},
    47  
    48  		{
    49  			scenario: "rewrite field 3",
    50  			in:       message{A: 21, B: 0.125, C: 0.0},
    51  			out:      message{A: 21, B: 0.125, C: 1.0},
    52  			rw: MessageRewriter{
    53  				3: FieldNumber(3).Float64(+1),
    54  			},
    55  		},
    56  
    57  		{
    58  			scenario: "rewrite field 4",
    59  			in:       message{A: 21, B: 0.125, C: 1.0, D: "A"},
    60  			out:      message{A: 21, B: 0.125, C: 1.0, D: "Hello World!"},
    61  			rw: MessageRewriter{
    62  				4: FieldNumber(4).String("Hello World!"),
    63  			},
    64  		},
    65  	}
    66  
    67  	for _, test := range tests {
    68  		t.Run(test.scenario, func(t *testing.T) {
    69  			b, err := Marshal(test.in)
    70  			if err != nil {
    71  				t.Fatal(err)
    72  			}
    73  
    74  			b, err = test.rw.Rewrite(nil, b)
    75  			if err != nil {
    76  				t.Fatal(err)
    77  			}
    78  
    79  			m := message{}
    80  			if err := Unmarshal(b, &m); err != nil {
    81  				t.Fatal(err)
    82  			}
    83  
    84  			if !reflect.DeepEqual(m, test.out) {
    85  				t.Errorf("messages mismatch:\nwant: %+v\ngot:  %+v", test.out, m)
    86  			}
    87  		})
    88  	}
    89  }
    90  
    91  func TestParseRewriteTemplate(t *testing.T) {
    92  	type submessage struct {
    93  		Question string `protobuf:"bytes,1,opt,name=question,proto3"`
    94  		Answer   string `protobuf:"bytes,2,opt,name=answer,proto3"`
    95  	}
    96  
    97  	type message struct {
    98  		Field1 bool `protobuf:"varint,1,opt,name=field_1,proto3"`
    99  
   100  		Field2 int   `protobuf:"varint,2,opt,name=field_2,proto3"`
   101  		Field3 int32 `protobuf:"varint,3,opt,name=field_3,proto3"`
   102  		Field4 int64 `protobuf:"varint,4,opt,name=field_4,proto3"`
   103  
   104  		Field5 uint   `protobuf:"varint,5,opt,name=field_5,proto3"`
   105  		Field6 uint32 `protobuf:"varint,6,opt,name=field_6,proto3"`
   106  		Field7 uint64 `protobuf:"varint,7,opt,name=field_7,proto3"`
   107  
   108  		Field8 int32 `protobuf:"zigzag32,8,opt,name=field_8,proto3"`
   109  		Field9 int64 `protobuf:"zigzag64,9,opt,name=field_9,proto3"`
   110  
   111  		Field10 float32 `protobuf:"fixed32,10,opt,name=field_10,proto3"`
   112  		Field11 float64 `protobuf:"fixed64,11,opt,name=field_11,proto3"`
   113  
   114  		Field12 string `protobuf:"bytes,12,opt,name=field_12,proto3"`
   115  		Field13 []byte `protobuf:"bytes,13,opt,name=field_13,proto3"`
   116  
   117  		Zero1 bool    `protobuf:"varint,21,opt,name=zero_1,proto3"`
   118  		Zero2 int     `protobuf:"varint,22,opt,name=zero_2,proto3"`
   119  		Zero3 int32   `protobuf:"varint,23,opt,name=zero_3,proto3"`
   120  		Zero4 int64   `protobuf:"varint,24,opt,name=zero_4,proto3"`
   121  		Zero5 uint    `protobuf:"varint,25,opt,name=zero_5,proto3"`
   122  		Zero6 uint32  `protobuf:"varint,26,opt,name=zero_6,proto3"`
   123  		Zero7 uint64  `protobuf:"varint,27,opt,name=zero_7,proto3"`
   124  		Zero8 float32 `protobuf:"fixed32,28,opt,name=zero_8,proto3"`
   125  		Zero9 float64 `protobuf:"fixed64,29,opt,name=zero_9,proto3"`
   126  
   127  		Subfield    *submessage  `protobuf:"bytes,99,opt,name=subfield,proto3"`
   128  		Submessages []submessage `protobuf:"bytes,100,rep,name=submessages,proto3"`
   129  
   130  		Mapping map[string]int `protobuf:"bytes,200,opt,name=mapping,proto3"`
   131  	}
   132  
   133  	original := &message{
   134  		Field1: false,
   135  
   136  		Field2: -1,
   137  		Field3: -2,
   138  		Field4: -3,
   139  
   140  		Field5: 1,
   141  		Field6: 2,
   142  		Field7: 3,
   143  
   144  		Field8: -10,
   145  		Field9: -11,
   146  
   147  		Field10: 1.0,
   148  		Field11: 2.0,
   149  
   150  		Field12: "field 12",
   151  		Field13: nil,
   152  
   153  		Zero1: true,
   154  		Zero2: 102,
   155  		Zero3: 103,
   156  		Zero4: 104,
   157  		Zero5: 105,
   158  		Zero6: 106,
   159  		Zero7: 107,
   160  		Zero8: 0.108,
   161  		Zero9: 0.109,
   162  
   163  		Subfield: &submessage{
   164  			Answer: "Good!",
   165  		},
   166  
   167  		Submessages: []submessage{
   168  			{Question: "Q1?", Answer: "A1"},
   169  			{Question: "Q2?", Answer: "A2"},
   170  			{Question: "Q3?", Answer: "A3"},
   171  		},
   172  
   173  		Mapping: map[string]int{
   174  			"hello": 1,
   175  			"world": 2,
   176  		},
   177  	}
   178  
   179  	expected := &message{
   180  		Field1: true,
   181  
   182  		Field2: 2,
   183  		Field3: 3,
   184  		Field4: 4,
   185  
   186  		Field5: 10,
   187  		Field6: 11,
   188  		Field7: 12,
   189  
   190  		Field8: -21,
   191  		Field9: -42,
   192  
   193  		Field10: 0.25,
   194  		Field11: 0.5,
   195  
   196  		Field12: "Hello!",
   197  		Field13: []byte("World!"),
   198  
   199  		Subfield: &submessage{
   200  			Question: "How are you?",
   201  			Answer:   "Good!",
   202  		},
   203  
   204  		Submessages: []submessage{
   205  			{Question: "Q1?", Answer: "A1"},
   206  			{Question: "Q2?", Answer: "A2"},
   207  			{Question: "Q3?", Answer: "Hello World!"},
   208  		},
   209  
   210  		Mapping: map[string]int{
   211  			"answer": 42,
   212  		},
   213  	}
   214  
   215  	rw, err := ParseRewriteTemplate(TypeOf(reflect.TypeOf(original)), []byte(`{
   216    "field_1": true,
   217  
   218    "field_2": 2,
   219    "field_3": 3,
   220    "field_4": 4,
   221  
   222    "field_5": 10,
   223    "field_6": 11,
   224    "field_7": 12,
   225  
   226    "field_8": -21,
   227    "field_9": -42,
   228  
   229    "field_10": 0.25,
   230    "field_11": 0.5,
   231  
   232    "field_12": "Hello!",
   233    "field_13": "World!",
   234  
   235    "zero_1": null,
   236    "zero_2": null,
   237    "zero_3": null,
   238    "zero_4": null,
   239    "zero_5": null,
   240    "zero_6": null,
   241    "zero_7": null,
   242    "zero_8": null,
   243    "zero_9": null,
   244  
   245    "subfield": {
   246      "question": "How are you?"
   247    },
   248  
   249    "submessages": [
   250      {
   251        "question": "Q1?",
   252        "answer": "A1"
   253      },
   254      {
   255        "question": "Q2?",
   256        "answer": "A2"
   257      },
   258      {
   259        "question": "Q3?",
   260        "answer": "Hello World!"
   261      }
   262    ],
   263  
   264    "mapping": {
   265      "answer": 42
   266    }
   267  }`))
   268  	if err != nil {
   269  		t.Fatal(err)
   270  	}
   271  
   272  	b1, err := Marshal(original)
   273  	if err != nil {
   274  		t.Fatal(err)
   275  	}
   276  
   277  	b2, err := rw.Rewrite(nil, b1)
   278  	if err != nil {
   279  		t.Fatal(err)
   280  	}
   281  
   282  	found := &message{}
   283  	if err := Unmarshal(b2, &found); err != nil {
   284  		t.Fatal(err)
   285  	}
   286  
   287  	if !reflect.DeepEqual(expected, found) {
   288  		t.Error("messages mismatch after rewrite")
   289  		t.Logf("want:\n%+v", expected)
   290  		t.Logf("got:\n%+v", found)
   291  	}
   292  }
   293  
   294  func BenchmarkRewrite(b *testing.B) {
   295  	type message struct {
   296  		A int
   297  		B float32
   298  		C float64
   299  		D string
   300  	}
   301  
   302  	in := message{A: 21, B: 0.125, D: "A"}
   303  	rw := MessageRewriter{
   304  		1: FieldNumber(1).Int(42),
   305  		2: FieldNumber(2).Float32(-1),
   306  		3: FieldNumber(3).Float64(+1),
   307  		4: FieldNumber(4).String("Hello World!"),
   308  	}
   309  
   310  	p, err := Marshal(in)
   311  	if err != nil {
   312  		b.Fatal(err)
   313  	}
   314  
   315  	out := make([]byte, 0, 2*cap(p))
   316  
   317  	for i := 0; i < b.N; i++ {
   318  		out, err = rw.Rewrite(out[:0], p)
   319  	}
   320  }
   321  
   322  func TestRewriteStructIdentity(t *testing.T) {
   323  	type Node struct {
   324  		Next               []Node   `protobuf:"bytes,1,rep,name=next,proto3" json:"next"`
   325  		Name               string   `protobuf:"bytes,2,opt,name=name,proto3" json:"name"`
   326  		Type               string   `protobuf:"bytes,3,opt,name=type,proto3" json:"type"`
   327  		On                 uint32   `protobuf:"varint,4,opt,name=on,proto3,enum=op.Status" json:"on,omitempty"`
   328  		Key                string   `protobuf:"bytes,5,opt,name=key,proto3" json:"key,omitempty"`
   329  		Seed               uint64   `protobuf:"fixed64,6,opt,name=seed,proto3" json:"seed,omitempty"`
   330  		ScheduleAfter      uint32   `protobuf:"varint,7,opt,name=schedule_after,json=scheduleAfter,proto3" json:"schedule_after,omitempty"`
   331  		ExpireAfter        uint32   `protobuf:"varint,8,opt,name=expire_after,json=expireAfter,proto3" json:"expire_after,omitempty"`
   332  		BackoffCoefficient uint32   `protobuf:"varint,9,opt,name=backoff_coefficient,json=backoffCoefficient,proto3" json:"backoff_coefficient,omitempty"`
   333  		BackoffMinDelay    uint32   `protobuf:"varint,10,opt,name=backoff_min_delay,json=backoffMinDelay,proto3" json:"backoff_min_delay,omitempty"`
   334  		BackoffMaxDelay    uint32   `protobuf:"varint,11,opt,name=backoff_max_delay,json=backoffMaxDelay,proto3" json:"backoff_max_delay,omitempty"`
   335  		ExecutionTimeout   uint32   `protobuf:"varint,12,opt,name=execution_timeout,json=executionTimeout,proto3" json:"execution_timeout,omitempty"`
   336  		NextLength         uint64   `protobuf:"varint,13,opt,name=next_length,json=nextLength,proto3" json:"next_length,omitempty"`
   337  		BatchMaxBytes      uint32   `protobuf:"varint,14,opt,name=batch_max_bytes,json=batchMaxBytes,proto3" json:"batch_max_bytes,omitempty"`
   338  		BatchMaxCount      uint32   `protobuf:"varint,15,opt,name=batch_max_count,json=batchMaxCount,proto3" json:"batch_max_count,omitempty"`
   339  		BatchTimeout       uint32   `protobuf:"varint,16,opt,name=batch_timeout,json=batchTimeout,proto3" json:"batch_timeout,omitempty"`
   340  		BatchKey           [16]byte `protobuf:"bytes,17,opt,name=batch_key,json=batchKey,proto3,customtype=U128" json:"batch_key"`
   341  	}
   342  
   343  	type Header struct {
   344  		Flows         string `protobuf:"bytes,1,opt,name=flows,proto3" json:"flows,omitempty"`
   345  		Root          Node   `protobuf:"bytes,2,opt,name=root,proto3" json:"root"`
   346  		TraceContext  []byte `protobuf:"bytes,6,opt,name=trace_context,json=traceContext,proto3" json:"trace_context"`
   347  		ContentLength int64  `protobuf:"varint,7,opt,name=content_length,json=contentLength,proto3" json:"content_length,omitempty"`
   348  		ContentType   string `protobuf:"bytes,8,opt,name=content_type,json=contentType,proto3" json:"content_type"`
   349  	}
   350  
   351  	b := []byte{
   352  		0xa, 0xd, 0x66, 0x6c, 0x6f, 0x77, 0x2d, 0x42, 0x3a, 0x66, 0x6c, 0x6f, 0x77, 0x2d, 0x30, 0x12,
   353  		0x7a, 0xa, 0x30, 0x12, 0xc, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x61, 0x72,
   354  		0x64, 0x1a, 0x0, 0x20, 0x2, 0x31, 0x69, 0xf2, 0xc9, 0xd0, 0xc1, 0x2f, 0xe0, 0x80, 0x68, 0x65,
   355  		0x8a, 0x1, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
   356  		0x0, 0x0, 0x0, 0x12, 0x4, 0x74, 0x65, 0x73, 0x74, 0x1a, 0x4, 0x68, 0x74, 0x74, 0x70, 0x31,
   357  		0xa, 0x7f, 0xf5, 0xf8, 0x13, 0x1d, 0xfb, 0x17, 0x38, 0xc1, 0xd, 0x40, 0xff, 0xdb, 0x1, 0x48,
   358  		0xc6, 0xf, 0x50, 0xbd, 0x1b, 0x58, 0x9a, 0xbe, 0x2, 0x60, 0x88, 0x27, 0x68, 0x5d, 0x70, 0x80,
   359  		0x80, 0x4, 0x78, 0xa, 0x80, 0x1, 0xd0, 0xf, 0x8a, 0x1, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0,
   360  		0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x32, 0x1c, 0xa, 0x10, 0x2a, 0x43,
   361  		0x4c, 0xf3, 0x8c, 0x67, 0x48, 0x8f, 0xe, 0xca, 0xe8, 0x28, 0x96, 0x6c, 0x2b, 0xe4, 0x12,
   362  		0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38, 0x91, 0x66, 0x42, 0x18, 0x61, 0x70,
   363  		0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x2d,
   364  		0x73, 0x74, 0x72, 0x65, 0x61, 0x6d,
   365  	}
   366  
   367  	m := Header{}
   368  	if err := Unmarshal(b, &m); err != nil {
   369  		t.Fatal(err)
   370  	}
   371  
   372  	r, err := ParseRewriteTemplate(TypeOf(reflect.TypeOf(m)), []byte(`{"root":{}}`))
   373  	if err != nil {
   374  		t.Fatal(err)
   375  	}
   376  
   377  	c, err := r.Rewrite(nil, b)
   378  	if err != nil {
   379  		t.Fatal(err)
   380  	}
   381  
   382  	x := Header{}
   383  	if err := Unmarshal(c, &x); err != nil {
   384  		t.Fatal(err)
   385  	}
   386  
   387  	if !reflect.DeepEqual(m, x) {
   388  		t.Errorf("messages mismatch")
   389  		t.Logf("want: %+v", m)
   390  		t.Logf("got:  %+v", x)
   391  	}
   392  }