<commit_before>// Copyright (c) 2017 <NAME> <<EMAIL>>.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package gonfig

import (
	"encoding/hex"
	"errors"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

var (
	testTimeStr = "2009-11-10T23:00:00Z"
	testTime    *time.Time
)

func init() {
	testTime = &time.Time{}
	if err := testTime.UnmarshalText([]byte(testTimeStr)); err != nil {
		panic(err)
	}
}

func stringPointer(s string) *string {
	return &s
}

type NotSupported interface {
	DoStuff() error
}

type MarshaledUpper []byte

func (m MarshaledUpper) String() string {
	return string(m)
}

func (m *MarshaledUpper) UnmarshalText(t []byte) error {
	*m = MarshaledUpper(strings.ToLower(string(t)))
	return nil
}

type ErrorMarshaler string

func (m *ErrorMarshaler) UnmarshalText(t []byte) error {
	return errors.New("error")
}

type HexEncoded []byte

func (h HexEncoded) String() string {
	s, _ := h.MarshalText()
	return string(s)
}

func (h HexEncoded) MarshalText() ([]byte, error) {
	return []byte(hex.EncodeToString([]byte(h))), nil
}

func (h *HexEncoded) UnmarshalText(t []byte) error {
	decoded, err := hex.DecodeString(string(t))
	if err != nil {
		return err
	}
	*h = decoded
	return nil
}

type NestedTestStruct struct {
	StringVar string      `default:"defstring2" short:"n" desc:"descstring2"`
	IntVar    int         `id:"int"`
	BoolVar1  bool        `id:"boolvar"`
	Hex       *HexEncoded `id:"hex"`
}

type TestStruct struct {
	StringVar  string  `default:"defstring" short:"s" desc:"descstring"`
	UintVar    uint    `default:"42"`
	IntVar     int     `default:"-42"`
	BoolVar1   bool    `short:"b"`
	BoolVar2   bool    `default:"true"`
	Float32Var float32 `id:"float" default:"0.50"`
	Float64Var float64 `default:"0.25"`

	Uint8Var      uint8
	Uint16Var     uint16
	Uint32Var     uint32
	Uint64Var     uint64
	Int8Var       int8
	Int16Var      int16
	Int32Var      int32 `id:"int-32-var"`
	Int64Var      int64
	ByteSliceVar1 []byte `id:"bytes1" opts:"hidden"`
	ByteSliceVar2 []byte `id:"bytes2" default:"AQID"`

	Strings1 []string `default:"string1,string2"`
	Strings2 []string `default:"string1,string2"`
	Strings3 []string `default:"string1,string2"`
	Strings4 []string `default:"string1,string2"`
	Ints1    []int    `id:"ints" default:"42,43"`
	Ints2    []int    `default:"42,43"`
	Uints1   []uint   `default:"42,44"`

	MapVar map[string]interface{}

	Nested      NestedTestStruct    `id:"nestedid"`
	NestedMulti []*NestedTestStruct `id:"nestedmultiid"`

	Marshaled *MarshaledUpper `id:"upper1"`
	HexData   *HexEncoded     `id:"hex"`
}

func setOS(args []string, env map[string]string) {
	// Set command line args.
	os.Args = append([]string{"test"}, args...)

	// Set environment.
	os.Clearenv()
	for k, v := range env {
		os.Setenv(k, v)
	}
}

func TestGonfig(t *testing.T) {
	testCases := []struct {
		desc string

		args        []string
		env         map[string]string
		fileContent string

		conf Conf

		config      interface{}
		shouldError bool
		shouldPanic bool
		validate    func(t *testing.T, config interface{})
	}{
		{
			desc: "default env and cli",
			args: []string{"-b",
				"--int16var", "42",
				"--int64var", "42",
				"--uint32var", "42",
				"--float", "-0.25",
				"--nestedid.int", "42",
				"-n", "otherstringvalue",
				"--strings1", "one", "--strings1", "two", "--strings1", "three",
				"--ints", "3", "--ints", "2", "--ints", "1",
				"--upper1", "TEST",
				"--hex", "010203",
				"--bytes1", "AQID",
				"--uints1", "40", "--uints1", "40",
				"--mapvar.mapkeyflag", "mapvalueflag",
			},
			env: map[string]string{
				"INT8VAR":               "42",
				"PREF_UINT64VAR":        "42",
				"PREF_INT_32_VAR":       "42",
				"PREF_INT16VAR":         "32",
				"PREF_NESTEDID_BOOLVAR": "true",<commit_msg>add test case for default-only<commit_after>// Copyright (c) 2017 <NAME> <<EMAIL>>.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package gonfig

import (
	"encoding/hex"
	"errors"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

var (
	testTimeStr = "2009-11-10T23:00:00Z"
	testTime    *time.Time
)

func init() {
	testTime = &time.Time{}
	if err := testTime.UnmarshalText([]byte(testTimeStr)); err != nil {
		panic(err)
	}
}

func stringPointer(s string) *string {
	return &s
}

type NotSupported interface {
	DoStuff() error
}

type MarshaledUpper []byte

func (m MarshaledUpper) String() string {
	return string(m)
}

func (m *MarshaledUpper) UnmarshalText(t []byte) error {
	*m = MarshaledUpper(strings.ToLower(string(t)))
	return nil
}

type ErrorMarshaler string

func (m *ErrorMarshaler) UnmarshalText(t []byte) error {
	return errors.New("error")
}

type HexEncoded []byte

func (h HexEncoded) String() string {
	s, _ := h.MarshalText()
	return string(s)
}

func (h HexEncoded) MarshalText() ([]byte, error) {
	return []byte(hex.EncodeToString([]byte(h))), nil
}

func (h *HexEncoded) UnmarshalText(t []byte) error {
	decoded, err := hex.DecodeString(string(t))
	if err != nil {
		return err
	}
	*h = decoded
	return nil
}

type NestedTestStruct struct {
	StringVar string      `default:"defstring2" short:"n" desc:"descstring2"`
	IntVar    int         `id:"int"`
	BoolVar1  bool        `id:"boolvar"`
	Hex       *HexEncoded `id:"hex"`
}

type TestStruct struct {
	StringVar  string  `default:"defstring" short:"s" desc:"descstring"`
	UintVar    uint    `default:"42"`
	IntVar     int     `default:"-42"`
	BoolVar1   bool    `short:"b"`
	BoolVar2   bool    `default:"true"`
	Float32Var float32 `id:"float" default:"0.50"`
	Float64Var float64 `default:"0.25"`

	Uint8Var      uint8
	Uint16Var     uint16
	Uint32Var     uint32
	Uint64Var     uint64
	Int8Var       int8
	Int16Var      int16
	Int32Var      int32 `id:"int-32-var"`
	Int64Var      int64
	ByteSliceVar1 []byte `id:"bytes1" opts:"hidden"`
	ByteSliceVar2 []byte `id:"bytes2" default:"AQID"`

	Strings1 []string `default:"string1,string2"`
	Strings2 []string `default:"string1,string2"`
	Strings3 []string `default:"string1,string2"`
	Strings4 []string `default:"string1,string2"`
	Ints1    []int    `id:"ints" default:"42,43"`
	Ints2    []int    `default:"42,43"`
	Uints1   []uint   `default:"42,44"`

	MapVar map[string]interface{}

	Nested      NestedTestStruct    `id:"nestedid"`
	NestedMulti []*NestedTestStruct `id:"nestedmultiid"`

	Marshaled *MarshaledUpper `id:"upper1"`
	HexData   *HexEncoded     `id:"hex"`
}

func setOS(args []string, env map[string]string) {
	// Set command line args.
	os.Args = append([]string{"test"}, args...)

	// Set environment.
	os.Clearenv()
	for k, v := range env {
		os.Setenv(k, v)
	}
}

func TestGonfig(t *testing.T) {
	testCases := []struct {
		desc string

		args        []string
		env         map[string]string
		fileContent string

		conf Conf

		config      interface{}
		shouldError bool
		shouldPanic bool
		validate    func(t *testing.T, config interface{})
	}{
		{
			desc: "only defaults",
			args: []string{},
			env:  map[string]string{},
			conf: Conf{
				FileDisable: true,
			},
			config: &TestStruct{},
			validate: func(t *testing.T, config interface{}) {
				c, success := config.(*TestStruct)
				require.True(t, success)

				assert.EqualValues(t, "defstring", c.StringVar)
				assert.EqualValues(t, 42, c.UintVar)
				assert.EqualValues(t, -42, c.IntVar)
				assert.EqualValues(t, false, c.BoolVar1)
				assert.EqualValues(t, true, c.BoolVar2)
				assert.EqualValues(t, 0.5, c.Float32Var)
				assert.EqualValues(t, 0.25, c.Float64Var)
				assert.EqualValues(t, 0, c.Int8Var)
				assert.EqualValues(t, 0, c.Int16Var)
				assert.EqualValues(t, 0, c.Int64Var)
				assert.EqualValues(t, 0, c.Uint32Var)
				assert.EqualValues(t, 0, c.Uint64Var)
				assert.EqualValues(t, 0, c.Int32Var)
				assert.EqualValues(t, "defstring2", c.Nested.StringVar)
				assert.EqualValues(t, false, c.Nested.BoolVar1)
				assert.EqualValues(t, 0, c.Nested.IntVar)
				assert.EqualValues(t, []byte(nil), c.ByteSliceVar1)
				assert.EqualValues(t, []byte{1, 2, 3}, c.ByteSliceVar2)
				assert.EqualValues(t, []string{"string1", "string2"}, c.Strings1)
				assert.EqualValues(t, []string{"string1", "string2"}, c.Strings2)
				assert.EqualValues(t, []string{"string1", "string2"}, c.Strings3)
				assert.EqualValues(t, []int{42, 43}, c.Ints1)
				assert.EqualValues(t, []int{42, 43}, c.Ints2)
				assert.EqualValues(t, []uint{42, 44}, c.Uints1)
			},
		},
		{
			desc: "default env and cli",
			args: []string{"-b",
				"--int16var", "42",
				"--int64var", "42",
				"--uint32var", "42",
				"--float", "-0.25",
				"--nestedid.int", "42",
				"-n", "otherstringvalue",
				"--strings1", "one", "--strings1", "two", "--strings1", "three",
				"--ints", "3", "--ints", "2", "--ints", "1",
				"--upper1", "TEST",
				"--hex", "010203",
				"--bytes1", "AQID",
				"--uints1", "40", "--uints1", "40",
				"--mapvar.mapkeyflag", "mapvalueflag",
			},
			env: map[string]string{
				"INT8VAR":               "42",
				"PREF_UINT64VAR":        "42",
				"PREF_INT_32_VAR":       "42",
				"PREF_INT16VAR":         "32",
				"PREF_NESTEDID_BOOLVAR": "true",
{'fraction_non_alphanumeric': 0.16890368302373027, 'fraction_numerical': 0.0401589176420058, 'mean_word_length': 3.503868471953578, 'pattern_counts': {'":': 10, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7506878', 'n_tokens_mistral': 3923, 'n_tokens_neox': 3441, 'n_words': 790}