Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ usage: fpbits decode FORMAT HEX...
fpbits sum FORMAT NUMBER...
```

Commands accept values as command-line arguments. For `decode`, `encode`, `convert`, and `sum`, a single `-` in place of the values reads whitespace-separated words from standard input. The input must be valid UTF-8; a leading byte-order mark is accepted.
Commands accept values as command-line arguments. For `decode`, `encode`, `convert`, and `sum`, a single `-` in place of the values reads whitespace-separated words from standard input. `next` also accepts a single `-` in place of HEX; standard input must then hold exactly one word. The input must be valid UTF-8; a leading byte-order mark is accepted.

Examples of commands include `fpbits decode f16 3c00`, `fpbits encode f16 0.1`, `fpbits convert f32 f16 3f800000`, `fpbits ulp f16 1`, `fpbits next --count 3 f16 3c00`, `fpbits range e4m3`, and `fpbits sum f16 2048 1 1`.

Expand Down
13 changes: 12 additions & 1 deletion internal/cli/cmd_next.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,18 @@ func RunNext(argv []string, stdin io.Reader) (string, error) {
if err != nil {
return "", err
}
bits, err := fp.ParseHex(format, parsed.Args[1])
hex := parsed.Args[1]
if hex == "-" {
words, err := core.Words(stdin, parsed.Args[1:])
if err != nil {
return "", err
}
if len(words) != 1 {
return "", core.Failf("<stdin>: expected 1 word, got %d", len(words))
}
hex = words[0]
}
bits, err := fp.ParseHex(format, hex)
if err != nil {
return "", err
}
Expand Down
82 changes: 82 additions & 0 deletions internal/cli/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1875,3 +1875,85 @@ error: 0e0
t.Errorf("sum with 401 significand digits returned (%d, %q, %q), want the complete literal diagnostic", status, stdout, stderr)
}
}

func TestNextReadsSingleHexWordFromStdin(t *testing.T) {
wantOutput := `offset bits value
-1 0x3bff 9.995e-1
0 0x3c00 1e0
+1 0x3c01 1.001e0
`
tests := []struct {
name string
args []string
input []byte
wantStatus int
wantStdout string
wantStderr string
}{
{
name: "one word",
args: []string{"next", "--count", "1", "f16", "-"},
input: []byte("3c00\n"),
wantStatus: 0,
wantStdout: wantOutput,
},
{
name: "byte-order mark, prefix, and CR LF",
args: []string{"next", "--count", "1", "f16", "-"},
input: []byte{0xef, 0xbb, 0xbf, '0', 'x', '3', 'c', '0', '0', '\r', '\n'},
wantStatus: 0,
wantStdout: wantOutput,
},
{
name: "two words",
args: []string{"next", "f16", "-"},
input: []byte("3c00 3c01\n"),
wantStatus: 2,
wantStderr: "fpbits: <stdin>: expected 1 word, got 2\n",
},
{
name: "no words",
args: []string{"next", "f16", "-"},
input: []byte(" \t\r\n"),
wantStatus: 2,
wantStderr: "fpbits: <stdin>: no input\n",
},
{
name: "invalid UTF-8",
args: []string{"next", "f16", "-"},
input: []byte{0x33, 0xff},
wantStatus: 2,
wantStderr: "fpbits: <stdin>: input is not valid UTF-8\n",
},
{
name: "bad hex word",
args: []string{"next", "f16", "-"},
input: []byte("3c0\n"),
wantStatus: 2,
wantStderr: "fpbits: invalid hex word \"3c0\" for f16 (expected 4 hex digits)\n",
},
{
name: "unknown format is reported before stdin is read",
args: []string{"next", "f17", "-"},
input: []byte{0xff},
wantStatus: 2,
wantStderr: "fpbits: unknown format \"f17\" (expected f16, bf16, f32, f64, e5m2 or e4m3)\n",
},
{
name: "too many arguments are reported before stdin is read",
args: []string{"next", "f16", "-", "3c00"},
input: []byte{0xff},
wantStatus: 2,
wantStderr: "fpbits: too many arguments\n",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
status, stdout, stderr, _, _ := runCLI(test.args, test.input)
if status != test.wantStatus || stdout != test.wantStdout || stderr != test.wantStderr {
t.Errorf("cli.Run(%q) = (%d, %q, %q), want (%d, %q, %q)", test.args, status, stdout, stderr, test.wantStatus, test.wantStdout, test.wantStderr)
}
})
}
}
Loading