blob: 99426c913bc043739ec0b3c186b630b388307ad6 [file] [log] [blame]
// Copyright 2020 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package flag
import (
"flag"
"fmt"
"testing"
"github.com/golang/protobuf/jsonpb"
"github.com/golang/protobuf/proto"
pb "go.chromium.org/luci/buildbucket/proto"
. "github.com/smartystreets/goconvey/convey"
. "go.chromium.org/luci/common/testing/assertions"
)
// special type that implements proto.Message interface for test purpose
type messageImpl string
func (messageImpl) Reset() {}
func (m messageImpl) String() string {
return string(m)
}
func (messageImpl) ProtoMessage() {}
// Assert that messageImpl implements to the proto.Message interface.
var _ = proto.Message(new(messageImpl))
func TestProtoMessageSliceFlag(t *testing.T) {
Convey("Basic", t, func() {
var builds []*pb.Build
fs := flag.NewFlagSet("test", flag.ContinueOnError)
flag := MessageSliceFlag(&builds)
fs.Var(flag, "build", "Test Proto Message")
var err error
err = flag.Set("{\"id\": 111111, \"status\": \"SUCCESS\"}")
So(err, ShouldBeNil)
err = flag.Set("{\"id\": 222222, \"status\": \"FAILURE\"}")
So(err, ShouldBeNil)
err = flag.Set("{\"id\": 333333, \"status\": \"CANCELED\"}")
So(err, ShouldBeNil)
So(flag.Get(), ShouldResembleProto, builds)
So(builds, ShouldHaveLength, 3)
So(builds[0].Id, ShouldEqual, 111111)
So(builds[0].Status, ShouldEqual, pb.Status_SUCCESS)
So(builds[1].Id, ShouldEqual, 222222)
So(builds[1].Status, ShouldEqual, pb.Status_FAILURE)
So(builds[2].Id, ShouldEqual, 333333)
So(builds[2].Status, ShouldEqual, pb.Status_CANCELED)
// Hard to set expectation for JSON string due to indentation
// and field order. Therefore, simply check if it's empty or not.
So(flag.String(), ShouldNotBeBlank)
})
Convey("Panic when input is not pointer", t, func() {
So(func() { MessageSliceFlag("a string") }, ShouldPanic)
})
Convey("Panic when input pointer dose not point to a slice", t, func() {
So(func() { MessageSliceFlag(&map[string]string{}) }, ShouldPanic)
})
Convey("Panic when element does not implement proto.Message", t, func() {
So(func() { MessageSliceFlag(&[]string{}) }, ShouldPanic)
})
Convey("Panic when element is not pointer", t, func() {
So(func() { MessageSliceFlag(&[]messageImpl{}) }, ShouldPanic)
})
Convey("Panic when element pointer does not point to a struct", t, func() {
So(func() { MessageSliceFlag(&[]*messageImpl{}) }, ShouldPanic)
})
}
func ExampleMessageSliceFlag() {
var builds []*pb.Build
fs := flag.NewFlagSet("test", flag.ContinueOnError)
flag := MessageSliceFlag(&builds)
fs.Var(flag, "build", "Test Proto Message")
fs.Parse([]string{"-build",
"{\"id\": 111111, \"status\": \"SUCCESS\"}"})
marshaler := &jsonpb.Marshaler{Indent: " "}
jsonMsg, _ := marshaler.MarshalToString(builds[0])
fmt.Println(jsonMsg)
// Output:
// {
// "id": "111111",
// "status": "SUCCESS"
// }
}