diff options
| author | 2020-11-03 20:04:52 +0100 | |
|---|---|---|
| committer | 2020-11-03 20:15:00 +0100 | |
| commit | 7f82f87c310a5db3933551fd0df3d0548abf9f7c (patch) | |
| tree | 28b7385f4f50934a98df4e032b40aedfcc76ae01 /clap | |
| parent | Replace `var` with `anytype` (diff) | |
| download | zig-clap-7f82f87c310a5db3933551fd0df3d0548abf9f7c.tar.gz zig-clap-7f82f87c310a5db3933551fd0df3d0548abf9f7c.tar.xz zig-clap-7f82f87c310a5db3933551fd0df3d0548abf9f7c.zip | |
Improve Diagnostic error message reporting
Diffstat (limited to 'clap')
| -rw-r--r-- | clap/args.zig | 2 | ||||
| -rw-r--r-- | clap/comptime.zig | 2 | ||||
| -rw-r--r-- | clap/streaming.zig | 92 |
3 files changed, 80 insertions, 16 deletions
diff --git a/clap/args.zig b/clap/args.zig index 4d97017..52626fc 100644 --- a/clap/args.zig +++ b/clap/args.zig | |||
| @@ -32,7 +32,7 @@ pub const SliceIterator = struct { | |||
| 32 | } | 32 | } |
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| 35 | test "clap.args.SliceIterator" { | 35 | test "SliceIterator" { |
| 36 | const args = &[_][]const u8{ "A", "BB", "CCC" }; | 36 | const args = &[_][]const u8{ "A", "BB", "CCC" }; |
| 37 | var iter = SliceIterator{ .args = args }; | 37 | var iter = SliceIterator{ .args = args }; |
| 38 | 38 | ||
diff --git a/clap/comptime.zig b/clap/comptime.zig index e8aae30..1570eaf 100644 --- a/clap/comptime.zig +++ b/clap/comptime.zig | |||
| @@ -146,7 +146,7 @@ pub fn ComptimeClap( | |||
| 146 | }; | 146 | }; |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | test "clap.comptime.ComptimeClap" { | 149 | test "" { |
| 150 | const Clap = ComptimeClap(clap.Help, clap.args.SliceIterator, comptime &[_]clap.Param(clap.Help){ | 150 | const Clap = ComptimeClap(clap.Help, clap.args.SliceIterator, comptime &[_]clap.Param(clap.Help){ |
| 151 | clap.parseParam("-a, --aa ") catch unreachable, | 151 | clap.parseParam("-a, --aa ") catch unreachable, |
| 152 | clap.parseParam("-b, --bb ") catch unreachable, | 152 | clap.parseParam("-b, --bb ") catch unreachable, |
diff --git a/clap/streaming.zig b/clap/streaming.zig index af57e8f..602d94a 100644 --- a/clap/streaming.zig +++ b/clap/streaming.zig | |||
| @@ -3,10 +3,12 @@ const clap = @import("../clap.zig"); | |||
| 3 | const std = @import("std"); | 3 | const std = @import("std"); |
| 4 | 4 | ||
| 5 | const args = clap.args; | 5 | const args = clap.args; |
| 6 | const testing = std.testing; | 6 | const debug = std.debug; |
| 7 | const heap = std.heap; | 7 | const heap = std.heap; |
| 8 | const io = std.io; | ||
| 8 | const mem = std.mem; | 9 | const mem = std.mem; |
| 9 | const os = std.os; | 10 | const os = std.os; |
| 11 | const testing = std.testing; | ||
| 10 | 12 | ||
| 11 | /// The result returned from ::StreamingClap.next | 13 | /// The result returned from ::StreamingClap.next |
| 12 | pub fn Arg(comptime Id: type) type { | 14 | pub fn Arg(comptime Id: type) type { |
| @@ -76,7 +78,7 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { | |||
| 76 | continue; | 78 | continue; |
| 77 | if (param.takes_value == .None) { | 79 | if (param.takes_value == .None) { |
| 78 | if (maybe_value != null) | 80 | if (maybe_value != null) |
| 79 | return err(diag, param.names, error.DoesntTakeValue); | 81 | return err(diag, arg, .{ .long = name }, error.DoesntTakeValue); |
| 80 | 82 | ||
| 81 | return Arg(Id){ .param = param }; | 83 | return Arg(Id){ .param = param }; |
| 82 | } | 84 | } |
| @@ -86,11 +88,13 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { | |||
| 86 | break :blk v; | 88 | break :blk v; |
| 87 | 89 | ||
| 88 | break :blk (try parser.iter.next()) orelse | 90 | break :blk (try parser.iter.next()) orelse |
| 89 | return err(diag, param.names, error.MissingValue); | 91 | return err(diag, arg, .{ .long = name }, error.MissingValue); |
| 90 | }; | 92 | }; |
| 91 | 93 | ||
| 92 | return Arg(Id){ .param = param, .value = value }; | 94 | return Arg(Id){ .param = param, .value = value }; |
| 93 | } | 95 | } |
| 96 | |||
| 97 | return err(diag, arg, .{ .long = name }, error.InvalidArgument); | ||
| 94 | }, | 98 | }, |
| 95 | .short => return try parser.chainging(.{ | 99 | .short => return try parser.chainging(.{ |
| 96 | .arg = full_arg, | 100 | .arg = full_arg, |
| @@ -105,10 +109,12 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { | |||
| 105 | 109 | ||
| 106 | return Arg(Id){ .param = param, .value = arg }; | 110 | return Arg(Id){ .param = param, .value = arg }; |
| 107 | } | 111 | } |
| 112 | |||
| 113 | return err(diag, arg, .{}, error.InvalidArgument); | ||
| 108 | }, | 114 | }, |
| 109 | } | 115 | } |
| 110 | 116 | ||
| 111 | return err(diag, .{ .long = arg }, error.InvalidArgument); | 117 | unreachable; |
| 112 | }, | 118 | }, |
| 113 | .chaining => |state| return try parser.chainging(state, diag), | 119 | .chaining => |state| return try parser.chainging(state, diag), |
| 114 | } | 120 | } |
| @@ -138,28 +144,32 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { | |||
| 138 | } | 144 | } |
| 139 | } | 145 | } |
| 140 | 146 | ||
| 141 | if (param.takes_value == .None) | 147 | const next_is_eql = if (next_index < arg.len) arg[next_index] == '=' else false; |
| 148 | if (param.takes_value == .None) { | ||
| 149 | if (next_is_eql) | ||
| 150 | return err(diag, arg, .{ .short = short }, error.DoesntTakeValue); | ||
| 142 | return Arg(Id){ .param = param }; | 151 | return Arg(Id){ .param = param }; |
| 152 | } | ||
| 143 | 153 | ||
| 144 | if (arg.len <= next_index) { | 154 | if (arg.len <= next_index) { |
| 145 | const value = (try parser.iter.next()) orelse | 155 | const value = (try parser.iter.next()) orelse |
| 146 | return err(diag, param.names, error.MissingValue); | 156 | return err(diag, arg, .{ .short = short }, error.MissingValue); |
| 147 | 157 | ||
| 148 | return Arg(Id){ .param = param, .value = value }; | 158 | return Arg(Id){ .param = param, .value = value }; |
| 149 | } | 159 | } |
| 150 | 160 | ||
| 151 | if (arg[next_index] == '=') | 161 | if (next_is_eql) |
| 152 | return Arg(Id){ .param = param, .value = arg[next_index + 1 ..] }; | 162 | return Arg(Id){ .param = param, .value = arg[next_index + 1 ..] }; |
| 153 | 163 | ||
| 154 | return Arg(Id){ .param = param, .value = arg[next_index..] }; | 164 | return Arg(Id){ .param = param, .value = arg[next_index..] }; |
| 155 | } | 165 | } |
| 156 | 166 | ||
| 157 | return err(diag, .{ .short = arg[index] }, error.InvalidArgument); | 167 | return err(diag, arg, .{ .short = arg[index] }, error.InvalidArgument); |
| 158 | } | 168 | } |
| 159 | 169 | ||
| 160 | fn err(diag: ?*clap.Diagnostic, names: clap.Names, _err: anytype) @TypeOf(_err) { | 170 | fn err(diag: ?*clap.Diagnostic, arg: []const u8, names: clap.Names, _err: anytype) @TypeOf(_err) { |
| 161 | if (diag) |d| | 171 | if (diag) |d| |
| 162 | d.name = names; | 172 | d.* = .{ .arg = arg, .name = names }; |
| 163 | return _err; | 173 | return _err; |
| 164 | } | 174 | } |
| 165 | }; | 175 | }; |
| @@ -187,7 +197,33 @@ fn testNoErr(params: []const clap.Param(u8), args_strings: []const []const u8, r | |||
| 187 | unreachable; | 197 | unreachable; |
| 188 | } | 198 | } |
| 189 | 199 | ||
| 190 | test "clap.streaming.StreamingClap: short params" { | 200 | fn testErr(params: []const clap.Param(u8), args_strings: []const []const u8, expected: []const u8) void { |
| 201 | var diag: clap.Diagnostic = undefined; | ||
| 202 | var iter = args.SliceIterator{ .args = args_strings }; | ||
| 203 | var c = StreamingClap(u8, args.SliceIterator){ | ||
| 204 | .params = params, | ||
| 205 | .iter = &iter, | ||
| 206 | }; | ||
| 207 | while (c.next(&diag) catch |err| { | ||
| 208 | var buf: [1024]u8 = undefined; | ||
| 209 | var slice_stream = io.fixedBufferStream(&buf); | ||
| 210 | diag.report(slice_stream.outStream(), err) catch unreachable; | ||
| 211 | |||
| 212 | const actual = slice_stream.getWritten(); | ||
| 213 | if (!mem.eql(u8, actual, expected)) { | ||
| 214 | debug.warn("\n============ Expected ============\n", .{}); | ||
| 215 | debug.warn("{}", .{expected}); | ||
| 216 | debug.warn("============= Actual =============\n", .{}); | ||
| 217 | debug.warn("{}", .{actual}); | ||
| 218 | testing.expect(false); | ||
| 219 | } | ||
| 220 | return; | ||
| 221 | }) |_| {} | ||
| 222 | |||
| 223 | testing.expect(false); | ||
| 224 | } | ||
| 225 | |||
| 226 | test "short params" { | ||
| 191 | const params = [_]clap.Param(u8){ | 227 | const params = [_]clap.Param(u8){ |
| 192 | clap.Param(u8){ | 228 | clap.Param(u8){ |
| 193 | .id = 0, | 229 | .id = 0, |
| @@ -239,7 +275,7 @@ test "clap.streaming.StreamingClap: short params" { | |||
| 239 | ); | 275 | ); |
| 240 | } | 276 | } |
| 241 | 277 | ||
| 242 | test "clap.streaming.StreamingClap: long params" { | 278 | test "long params" { |
| 243 | const params = [_]clap.Param(u8){ | 279 | const params = [_]clap.Param(u8){ |
| 244 | clap.Param(u8){ | 280 | clap.Param(u8){ |
| 245 | .id = 0, | 281 | .id = 0, |
| @@ -283,7 +319,7 @@ test "clap.streaming.StreamingClap: long params" { | |||
| 283 | ); | 319 | ); |
| 284 | } | 320 | } |
| 285 | 321 | ||
| 286 | test "clap.streaming.StreamingClap: positional params" { | 322 | test "positional params" { |
| 287 | const params = [_]clap.Param(u8){clap.Param(u8){ | 323 | const params = [_]clap.Param(u8){clap.Param(u8){ |
| 288 | .id = 0, | 324 | .id = 0, |
| 289 | .takes_value = .One, | 325 | .takes_value = .One, |
| @@ -299,7 +335,7 @@ test "clap.streaming.StreamingClap: positional params" { | |||
| 299 | ); | 335 | ); |
| 300 | } | 336 | } |
| 301 | 337 | ||
| 302 | test "clap.streaming.StreamingClap: all params" { | 338 | test "all params" { |
| 303 | const params = [_]clap.Param(u8){ | 339 | const params = [_]clap.Param(u8){ |
| 304 | clap.Param(u8){ | 340 | clap.Param(u8){ |
| 305 | .id = 0, | 341 | .id = 0, |
| @@ -366,3 +402,31 @@ test "clap.streaming.StreamingClap: all params" { | |||
| 366 | }, | 402 | }, |
| 367 | ); | 403 | ); |
| 368 | } | 404 | } |
| 405 | |||
| 406 | test "errors" { | ||
| 407 | const params = [_]clap.Param(u8){ | ||
| 408 | clap.Param(u8){ | ||
| 409 | .id = 0, | ||
| 410 | .names = clap.Names{ | ||
| 411 | .short = 'a', | ||
| 412 | .long = "aa", | ||
| 413 | }, | ||
| 414 | }, | ||
| 415 | clap.Param(u8){ | ||
| 416 | .id = 1, | ||
| 417 | .names = clap.Names{ | ||
| 418 | .short = 'c', | ||
| 419 | .long = "cc", | ||
| 420 | }, | ||
| 421 | .takes_value = .One, | ||
| 422 | }, | ||
| 423 | }; | ||
| 424 | testErr(¶ms, &[_][]const u8{"q"}, "Invalid argument 'q'\n"); | ||
| 425 | testErr(¶ms, &[_][]const u8{"-q"}, "Invalid argument '-q'\n"); | ||
| 426 | testErr(¶ms, &[_][]const u8{"--q"}, "Invalid argument '--q'\n"); | ||
| 427 | testErr(¶ms, &[_][]const u8{"--q=1"}, "Invalid argument '--q'\n"); | ||
| 428 | testErr(¶ms, &[_][]const u8{"-a=1"}, "The argument '-a' does not take a value\n"); | ||
| 429 | testErr(¶ms, &[_][]const u8{"--aa=1"}, "The argument '--aa' does not take a value\n"); | ||
| 430 | testErr(¶ms, &[_][]const u8{"-c"}, "The argument '-c' requires a value but none was supplied\n"); | ||
| 431 | testErr(¶ms, &[_][]const u8{"--cc"}, "The argument '--cc' requires a value but none was supplied\n"); | ||
| 432 | } | ||