コード例 #1
0
ファイル: strconvx_test.go プロジェクト: read-later/bazil
func TestInt(t *testing.T) {
	var x int
	err := strconvx.Parse(&x, "1")
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if g, e := x, int(1); g != e {
		t.Errorf("Unexpected result: %v != %v", g, e)
	}
}
コード例 #2
0
ファイル: strconvx_test.go プロジェクト: read-later/bazil
func TestInt8OverFlow(t *testing.T) {
	var x int8
	err := strconvx.Parse(&x, "9000")
	if err == nil {
		t.Fatalf("Expected an error")
	}
	if g, e := err.Error(), `strconv.ParseInt: parsing "9000": value out of range`; g != e {
		t.Errorf("Wrong error message: %q != %q", g, e)
	}
}
コード例 #3
0
ファイル: strconvx_test.go プロジェクト: read-later/bazil
func TestUintOverflow(t *testing.T) {
	if !is32bit {
		t.Skip("not on 32-bit architecture")
	}

	var x uint
	err := strconvx.Parse(&x, "4294967296")
	if err == nil {
		t.Fatalf("Expected an error")
	}
	if g, e := err.Error(), `strconv.ParseInt: parsing "4294967296": value out of range`; g != e {
		t.Errorf("Wrong error message: %q != %q", g, e)
	}
}
コード例 #4
0
ファイル: parse.go プロジェクト: read-later/bazil
// Parse fills the fields of the struct pointed to by args with input
// from the given list.
//
// Fields are handled based on their data type, for example strings
// are converted into integers when necessary.
//
// In addition to built-in conversion rules, if a field implements
// Setter, the Set method is called to do the conversion. This
// interface is compatible with flag.Value.
//
// To mark fields optional, insert an Optional marker in the struct
// after the last mandatory field.
//
// To consume any number of arguments, use a slice as the last field.
//
// Parse returns an error of type ErrMissingMandatoryArg if a mandatory
// field was not filled.
//
// Parse returns an error of type ErrTooManyArgs if there are more
// arguments than (non-slice) fields.
func Parse(args interface{}, list []string) error {
	pointer := reflect.ValueOf(args).Elem()
	if !pointer.CanSet() {
		return errors.New("must pass a pointer to positional.Parse")
	}
	value := reflect.Indirect(pointer)
	mandatory := true

	idx := 0

	for {

		if idx >= value.NumField() {
			break
		}

		if value.Type().Field(idx).Type == reflect.TypeOf(Optional{}) {
			mandatory = false
			idx++
			continue
		}

		if len(list) == 0 {
			if mandatory {
				name := meta(value.Type().Field(idx))
				return ErrMissingMandatoryArg{Name: name}
			}
			// only optional fields left and we ran out of args; ok
			break
		}

		field := value.Field(idx)
		switch field.Kind() {
		case reflect.Slice:
			if idx != value.NumField()-1 {
				return errors.New("cannot have items in argument struct after a slice element")
			}
			// consider mandatory requirement fulfilled
			mandatory = false

			v := reflect.Append(field, reflect.ValueOf(list[0]))
			field.Set(v)
			// do NOT advance idx; slice takes rest of args

		default:
			v, ok := field.Addr().Interface().(Setter)
			if ok {
				err := v.Set(list[0])
				if err != nil {
					return err
				}
			} else {
				if field.Kind() == reflect.Ptr {
					// instantiate a new value, parse into it
					val := reflect.New(field.Type().Elem())
					field.Set(val)
					field = val.Elem()
				}
				err := strconvx.Parse(field.Addr().Interface(), list[0])
				if err != nil {
					return err
				}
			}
			idx++
		}
		list = list[1:]
	}

	if len(list) > 0 {
		return ErrTooManyArgs{}
	}
	return nil
}