/*
 *
 * Copyright 2019 gRPC 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 flags

import (
	"flag"
	"reflect"
	"testing"
	"time"

	"google.golang.org/grpc/internal/grpctest"
)

type s struct {
	grpctest.Tester
}

func Test(t *testing.T) {
	grpctest.RunSubTests(t, s{})
}

func (s) TestStringWithAllowedValues(t *testing.T) {
	const defaultVal = "default"
	tests := []struct {
		args    string
		allowed []string
		wantVal string
		wantErr bool
	}{
		{"-workloads=all", []string{"unary", "streaming", "all"}, "all", false},
		{"-workloads=disallowed", []string{"unary", "streaming", "all"}, defaultVal, true},
	}

	for _, test := range tests {
		flag.CommandLine = flag.NewFlagSet("test", flag.ContinueOnError)
		var w = StringWithAllowedValues("workloads", defaultVal, "usage", test.allowed)
		err := flag.CommandLine.Parse([]string{test.args})
		switch {
		case !test.wantErr && err != nil:
			t.Errorf("failed to parse command line args {%v}: %v", test.args, err)
		case test.wantErr && err == nil:
			t.Errorf("flag.Parse(%v) = nil, want non-nil error", test.args)
		default:
			if *w != test.wantVal {
				t.Errorf("flag value is %v, want %v", *w, test.wantVal)
			}
		}
	}
}

func (s) TestDurationSlice(t *testing.T) {
	defaultVal := []time.Duration{time.Second, time.Nanosecond}
	tests := []struct {
		args    string
		wantVal []time.Duration
		wantErr bool
	}{
		{"-latencies=1s", []time.Duration{time.Second}, false},
		{"-latencies=1s,2s,3s", []time.Duration{time.Second, 2 * time.Second, 3 * time.Second}, false},
		{"-latencies=bad", defaultVal, true},
	}

	for _, test := range tests {
		flag.CommandLine = flag.NewFlagSet("test", flag.ContinueOnError)
		var w = DurationSlice("latencies", defaultVal, "usage")
		err := flag.CommandLine.Parse([]string{test.args})
		switch {
		case !test.wantErr && err != nil:
			t.Errorf("failed to parse command line args {%v}: %v", test.args, err)
		case test.wantErr && err == nil:
			t.Errorf("flag.Parse(%v) = nil, want non-nil error", test.args)
		default:
			if !reflect.DeepEqual(*w, test.wantVal) {
				t.Errorf("flag value is %v, want %v", *w, test.wantVal)
			}
		}
	}
}

func (s) TestIntSlice(t *testing.T) {
	defaultVal := []int{1, 1024}
	tests := []struct {
		args    string
		wantVal []int
		wantErr bool
	}{
		{"-kbps=1", []int{1}, false},
		{"-kbps=1,2,3", []int{1, 2, 3}, false},
		{"-kbps=20e4", defaultVal, true},
	}

	for _, test := range tests {
		flag.CommandLine = flag.NewFlagSet("test", flag.ContinueOnError)
		var w = IntSlice("kbps", defaultVal, "usage")
		err := flag.CommandLine.Parse([]string{test.args})
		switch {
		case !test.wantErr && err != nil:
			t.Errorf("failed to parse command line args {%v}: %v", test.args, err)
		case test.wantErr && err == nil:
			t.Errorf("flag.Parse(%v) = nil, want non-nil error", test.args)
		default:
			if !reflect.DeepEqual(*w, test.wantVal) {
				t.Errorf("flag value is %v, want %v", *w, test.wantVal)
			}
		}
	}
}

func (s) TestStringSlice(t *testing.T) {
	defaultVal := []string{"bar", "baz"}
	tests := []struct {
		args    string
		wantVal []string
		wantErr bool
	}{
		{"-name=foobar", []string{"foobar"}, false},
		{"-name=foo,bar", []string{"foo", "bar"}, false},
		{`-name="foo,bar",baz`, []string{"foo,bar", "baz"}, false},
		{`-name="foo,bar""",baz`, []string{`foo,bar"`, "baz"}, false},
	}

	for _, test := range tests {
		flag.CommandLine = flag.NewFlagSet("test", flag.ContinueOnError)
		var w = StringSlice("name", defaultVal, "usage")
		err := flag.CommandLine.Parse([]string{test.args})
		switch {
		case !test.wantErr && err != nil:
			t.Errorf("failed to parse command line args {%v}: %v", test.args, err)
		case test.wantErr && err == nil:
			t.Errorf("flag.Parse(%v) = nil, want non-nil error", test.args)
		default:
			if !reflect.DeepEqual(*w, test.wantVal) {
				t.Errorf("flag value is %v, want %v", *w, test.wantVal)
			}
		}
	}
}
