summaryrefslogtreecommitdiff
path: root/clap/streaming.zig
diff options
context:
space:
mode:
Diffstat (limited to 'clap/streaming.zig')
-rw-r--r--clap/streaming.zig92
1 files changed, 78 insertions, 14 deletions
diff --git a/clap/streaming.zig b/clap/streaming.zig
index 90c4e02..8ab01f6 100644
--- a/clap/streaming.zig
+++ b/clap/streaming.zig
@@ -3,10 +3,12 @@ const clap = @import("../clap.zig");
3const std = @import("std"); 3const std = @import("std");
4 4
5const args = clap.args; 5const args = clap.args;
6const testing = std.testing; 6const debug = std.debug;
7const heap = std.heap; 7const heap = std.heap;
8const io = std.io;
8const mem = std.mem; 9const mem = std.mem;
9const os = std.os; 10const os = std.os;
11const testing = std.testing;
10 12
11/// The result returned from ::StreamingClap.next 13/// The result returned from ::StreamingClap.next
12pub fn Arg(comptime Id: type) type { 14pub 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: var) @TypeOf(_err) { 170 fn err(diag: ?*clap.Diagnostic, arg: []const u8, names: clap.Names, _err: var) @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
190test "clap.streaming.StreamingClap: short params" { 200fn 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
226test "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
242test "clap.streaming.StreamingClap: long params" { 278test "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
286test "clap.streaming.StreamingClap: positional params" { 322test "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
302test "clap.streaming.StreamingClap: all params" { 338test "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
406test "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(&params, &[_][]const u8{"q"}, "Invalid argument 'q'\n");
425 testErr(&params, &[_][]const u8{"-q"}, "Invalid argument '-q'\n");
426 testErr(&params, &[_][]const u8{"--q"}, "Invalid argument '--q'\n");
427 testErr(&params, &[_][]const u8{"--q=1"}, "Invalid argument '--q'\n");
428 testErr(&params, &[_][]const u8{"-a=1"}, "The argument '-a' does not take a value\n");
429 testErr(&params, &[_][]const u8{"--aa=1"}, "The argument '--aa' does not take a value\n");
430 testErr(&params, &[_][]const u8{"-c"}, "The argument '-c' requires a value but none was supplied\n");
431 testErr(&params, &[_][]const u8{"--cc"}, "The argument '--cc' requires a value but none was supplied\n");
432}