go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/lucicfg/protos_test.go (about)

     1  // Copyright 2018 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package lucicfg
    16  
    17  import (
    18  	"os"
    19  	"testing"
    20  
    21  	"go.starlark.net/starlark"
    22  
    23  	"google.golang.org/protobuf/proto"
    24  	"google.golang.org/protobuf/types/descriptorpb"
    25  
    26  	"go.chromium.org/luci/common/proto/textpb"
    27  	"go.chromium.org/luci/starlark/starlarkproto"
    28  
    29  	. "github.com/smartystreets/goconvey/convey"
    30  )
    31  
    32  // testMessageType represents testproto.Msg from misc/support/test.proto as
    33  // loaded through starlarkproto Loader.
    34  //
    35  // Used by testMessage and testMessageProto.
    36  var testMessageType *starlarkproto.MessageType
    37  
    38  func init() {
    39  	// See testdata/gen.go for where this file is generated.
    40  	blob, err := os.ReadFile("testdata/misc/support/test_descpb.bin")
    41  	if err != nil {
    42  		panic(err)
    43  	}
    44  	dspb := &descriptorpb.FileDescriptorSet{}
    45  	if err := proto.Unmarshal(blob, dspb); err != nil {
    46  		panic(err)
    47  	}
    48  	ds, err := starlarkproto.NewDescriptorSet("test", dspb.GetFile(), []*starlarkproto.DescriptorSet{
    49  		luciTypesDescSet, // for "go.chromium.org/luci/common/proto/options.proto"
    50  	})
    51  	if err != nil {
    52  		panic(err)
    53  	}
    54  	testProtoLoader := starlarkproto.NewLoader()
    55  	if err := testProtoLoader.AddDescriptorSet(ds); err != nil {
    56  		panic(err)
    57  	}
    58  	testproto, err := testProtoLoader.Module("misc/support/test.proto")
    59  	if err != nil {
    60  		panic(err)
    61  	}
    62  	msgT, err := testproto.Attr("Msg")
    63  	if err != nil {
    64  		panic(err)
    65  	}
    66  	testMessageType = msgT.(*starlarkproto.MessageType)
    67  }
    68  
    69  // testMessage returns new testproto.Msg as a Starlark value to be used from
    70  // tests (grabs it via testProtoLoader).
    71  func testMessage(i int, f float64) *starlarkproto.Message {
    72  	msg := testMessageType.Message()
    73  	if err := msg.SetField("i", starlark.MakeInt(i)); err != nil {
    74  		panic(err)
    75  	}
    76  	if err := msg.SetField("f", starlark.Float(f)); err != nil {
    77  		panic(err)
    78  	}
    79  	return msg
    80  }
    81  
    82  // testMessageProto returns new testproto.Msg as proto.Message, deserializing
    83  // it from a text proto.
    84  func testMessageProto(body string) proto.Message {
    85  	msg, err := starlarkproto.FromTextPB(testMessageType, []byte(body), false)
    86  	if err != nil {
    87  		panic(err)
    88  	}
    89  	return msg.ToProto()
    90  }
    91  
    92  func TestProtos(t *testing.T) {
    93  	t.Parallel()
    94  
    95  	// Note: testMessage() is used by other tests. This test verifies it works
    96  	// at all.
    97  	Convey("testMessage works", t, func() {
    98  		i, err := testMessage(123, 0).Attr("i")
    99  		So(err, ShouldBeNil)
   100  		asInt, err := starlark.AsInt32(i)
   101  		So(err, ShouldBeNil)
   102  		So(asInt, ShouldEqual, 123)
   103  	})
   104  
   105  	Convey("testMessageProto works", t, func() {
   106  		msg := testMessageProto("i: 456")
   107  		blob, err := textpb.Marshal(msg)
   108  		So(err, ShouldBeNil)
   109  		So(string(blob), ShouldEqual, "i: 456\n")
   110  	})
   111  
   112  	Convey("Doc URL works", t, func() {
   113  		name, doc := protoMessageDoc(testMessage(123, 0))
   114  		So(name, ShouldEqual, "Msg")
   115  		So(doc, ShouldEqual, "https://example.com/proto-doc") // see misc/support/test.proto
   116  	})
   117  
   118  	Convey("semanticallyEqual: true", t, func() {
   119  		msg1 := testMessageProto(`
   120  			i: 123
   121  			nested: {
   122  				s: "aaa"
   123  				ignore: "ignore 1"
   124  			}
   125  			ignore_scalar: "ignore 1"
   126  			ignore_rep: "ignore 1"
   127  			ignore_rep: "ignore 1"
   128  			ignore_nested: {
   129  				s: "ignore 1"
   130  			}
   131  		`)
   132  		msg2 := testMessageProto(`
   133  			i: 123
   134  			nested: {
   135  				s: "aaa"
   136  				ignore: "ignore 2"
   137  			}
   138  			ignore_scalar: "ignore 2"
   139  			ignore_rep: "ignore 2"
   140  			ignore_rep: "ignore 2"
   141  			ignore_nested: {
   142  				s: "ignore 2"
   143  			}
   144  		`)
   145  		So(semanticallyEqual(msg1, msg2), ShouldBeTrue)
   146  	})
   147  
   148  	Convey("semanticallyEqual: false", t, func() {
   149  		msg1 := testMessageProto(`
   150  			i: 123
   151  			nested: {
   152  				s: "aaa"
   153  				ignore: "ignore 1"
   154  			}
   155  			ignore_scalar: "ignore 1"
   156  			ignore_rep: "ignore 1"
   157  			ignore_rep: "ignore 1"
   158  			ignore_nested: {
   159  				s: "ignore 1"
   160  			}
   161  		`)
   162  		msg2 := testMessageProto(`
   163  			i: 123
   164  			nested: {
   165  				s: "bbb"
   166  				ignore: "ignore 2"
   167  			}
   168  			ignore_scalar: "ignore 2"
   169  			ignore_rep: "ignore 2"
   170  			ignore_rep: "ignore 2"
   171  			ignore_nested: {
   172  				s: "ignore 2"
   173  			}
   174  		`)
   175  		So(semanticallyEqual(msg1, msg2), ShouldBeFalse)
   176  	})
   177  }