Skip to content

Improve handling of negative numbers#285

Merged
alexflint merged 1 commit intomasterfrom
negative-numbers
May 24, 2025
Merged

Improve handling of negative numbers#285
alexflint merged 1 commit intomasterfrom
negative-numbers

Conversation

@alexflint
Copy link
Copy Markdown
Owner

Fixes #60 #284

The main corner case I'm considering in this PR is when there are arguments like -4, -6 defined as flags, as in

var args struct {
    UseIPv4 bool `arg:"-4"`
    UseIPv6 bool `arg:"-6"`
}

There are a few core linux utilities such as ping that set a precedent for having numeric flags like this, so it's a case I do want to support. However, supporting this means that if you have an argument struct like this:

var args struct {
    Floats []float64 `arg:"--floats"`
    UseIPv4 bool `arg:"-4"`
    UseIPv6 bool `arg:"-6"`
}

and you write on the command line ./program --floats -1.2 -3.4 -6, then there's a question of whether the last -6 should go into Floats or into UseIPv6 in this example.

What this PR implements is that if you have a numeric flag like UseIPv6 in the above example, then that will take precedence, but otherwise -6 will be treated as a number and put into Floats.

This is only implemented for arguments, not positional, in this PR. Here are some test cases that should give a sense of what's implemented:

func TestNegativeInt(t *testing.T) {
	var args struct {
		Foo int
	}
	err := parse("-foo -100", &args)
	require.NoError(t, err)
	assert.EqualValues(t, args.Foo, -100)
}

func TestNegativeFloat(t *testing.T) {
	var args struct {
		Foo float64
	}
	err := parse("-foo -99", &args)
	require.NoError(t, err)
	assert.EqualValues(t, args.Foo, -99)
}

func TestNumericFlag(t *testing.T) {
	var args struct {
		UseIPv6 bool `arg:"-6"`
		Foo     int
	}
	err := parse("-6", &args)
	require.NoError(t, err)
	assert.EqualValues(t, args.UseIPv6, true)
}

func TestNumericFlagTakesPrecedence(t *testing.T) {
	var args struct {
		UseIPv6 bool `arg:"-6"`
		Foo     int
	}
	err := parse("-foo -6", &args)
	require.Error(t, err)
}

func TestRepeatedNegativeInts(t *testing.T) {
	var args struct {
		Ints []int `arg:"--numbers"`
	}
	err := parse("--numbers -1 -2 -6", &args)
	require.NoError(t, err)
	assert.EqualValues(t, args.Ints, []int{-1, -2, -6})
}

func TestRepeatedNegativeFloats(t *testing.T) {
	var args struct {
		Floats []float32 `arg:"--numbers"`
	}
	err := parse("--numbers -1 -2 -6", &args)
	require.NoError(t, err)
	assert.EqualValues(t, args.Floats, []float32{-1, -2, -6})
}

func TestRepeatedNegativeFloatsThenNumericFlag(t *testing.T) {
	var args struct {
		Floats  []float32 `arg:"--numbers"`
		UseIPv6 bool      `arg:"-6"`
	}
	err := parse("--numbers -1 -2 -6", &args)
	require.NoError(t, err)
	assert.EqualValues(t, args.Floats, []float32{-1, -2})
	assert.True(t, args.UseIPv6)
}

func TestRepeatedNegativeFloatsThenNonexistentFlag(t *testing.T) {
	var args struct {
		Floats  []float32 `arg:"--numbers"`
		UseIPv6 bool      `arg:"-6"`
	}
	err := parse("--numbers -1 -2 -n", &args)
	require.Error(t, err, "unknown argument -n")
}

func TestRepeatedNegativeIntsThenFloat(t *testing.T) {
	var args struct {
		Ints []int `arg:"--numbers"`
	}
	err := parse("--numbers -1 -2 -0.1", &args)
	require.Error(t, err, "unknown argument -0.1")
}

func TestNegativeIntAndFloatAndTricks(t *testing.T) {
	var args struct {
		Foo int
		Bar float64
		N   int `arg:"--100"`
	}
	err := parse("-foo -99 -bar -60.14 -100 -101", &args)
	require.NoError(t, err)
	assert.EqualValues(t, args.Foo, -99)
	assert.EqualValues(t, args.Bar, -60.14)
	assert.EqualValues(t, args.N, -101)
}

@alexflint alexflint changed the title improve handling of negative numbers Improve handling of negative numbers May 23, 2025
@alexflint alexflint merged commit a36ed1e into master May 24, 2025
3 checks passed
@alexflint alexflint deleted the negative-numbers branch May 24, 2025 12:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Negative values are impossible to parse

1 participant