mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
std.fmt: Add unit tests for all methods in the Parser struct
This commit is contained in:
parent
8d914ea734
commit
4162f401cb
249
lib/std/fmt.zig
249
lib/std/fmt.zig
@ -11,6 +11,7 @@ const unicode = std.unicode;
|
|||||||
const meta = std.meta;
|
const meta = std.meta;
|
||||||
const lossyCast = math.lossyCast;
|
const lossyCast = math.lossyCast;
|
||||||
const expectFmt = std.testing.expectFmt;
|
const expectFmt = std.testing.expectFmt;
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
pub const default_max_depth = 3;
|
pub const default_max_depth = 3;
|
||||||
|
|
||||||
@ -319,7 +320,6 @@ pub const Specifier = union(enum) {
|
|||||||
/// Allows to implement formatters compatible with std.fmt without replicating
|
/// Allows to implement formatters compatible with std.fmt without replicating
|
||||||
/// the standard library behavior.
|
/// the standard library behavior.
|
||||||
pub const Parser = struct {
|
pub const Parser = struct {
|
||||||
pos: usize = 0,
|
|
||||||
iter: std.unicode.Utf8Iterator,
|
iter: std.unicode.Utf8Iterator,
|
||||||
|
|
||||||
// Returns a decimal number or null if the current character is not a
|
// Returns a decimal number or null if the current character is not a
|
||||||
@ -345,16 +345,17 @@ pub const Parser = struct {
|
|||||||
// Returns a substring of the input starting from the current position
|
// Returns a substring of the input starting from the current position
|
||||||
// and ending where `ch` is found or until the end if not found
|
// and ending where `ch` is found or until the end if not found
|
||||||
pub fn until(self: *@This(), ch: u21) []const u8 {
|
pub fn until(self: *@This(), ch: u21) []const u8 {
|
||||||
var result: []const u8 = &[_]u8{};
|
const start = self.iter.i;
|
||||||
while (self.peek(0)) |code_point| {
|
while (self.peek(0)) |code_point| {
|
||||||
if (code_point == ch)
|
if (code_point == ch)
|
||||||
break;
|
break;
|
||||||
result = result ++ (self.iter.nextCodepointSlice() orelse &[_]u8{});
|
_ = self.iter.nextCodepoint();
|
||||||
}
|
}
|
||||||
return result;
|
return self.iter.bytes[start..self.iter.i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns one character, if available
|
// Returns the character pointed to by the iterator if available, or
|
||||||
|
// null otherwise
|
||||||
pub fn char(self: *@This()) ?u21 {
|
pub fn char(self: *@This()) ?u21 {
|
||||||
if (self.iter.nextCodepoint()) |code_point| {
|
if (self.iter.nextCodepoint()) |code_point| {
|
||||||
return code_point;
|
return code_point;
|
||||||
@ -362,6 +363,8 @@ pub const Parser = struct {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns true if the iterator points to an existing character and
|
||||||
|
// false otherwise
|
||||||
pub fn maybe(self: *@This(), val: u21) bool {
|
pub fn maybe(self: *@This(), val: u21) bool {
|
||||||
if (self.peek(0) == val) {
|
if (self.peek(0) == val) {
|
||||||
_ = self.iter.nextCodepoint();
|
_ = self.iter.nextCodepoint();
|
||||||
@ -2779,3 +2782,239 @@ test hex {
|
|||||||
try std.testing.expectEqualStrings("[00efcdab78563412]", s);
|
try std.testing.expectEqualStrings("[00efcdab78563412]", s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "parser until" {
|
||||||
|
{ // return substring till ':'
|
||||||
|
var parser: Parser = .{
|
||||||
|
.iter = .{ .bytes = "abc:1234", .i = 0 },
|
||||||
|
};
|
||||||
|
try testing.expectEqualStrings("abc", parser.until(':'));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // return the entire string - `ch` not found
|
||||||
|
var parser: Parser = .{
|
||||||
|
.iter = .{ .bytes = "abc1234", .i = 0 },
|
||||||
|
};
|
||||||
|
try testing.expectEqualStrings("abc1234", parser.until(':'));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // substring is empty - `ch` is the only character
|
||||||
|
var parser: Parser = .{
|
||||||
|
.iter = .{ .bytes = ":", .i = 0 },
|
||||||
|
};
|
||||||
|
try testing.expectEqualStrings("", parser.until(':'));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // empty string and `ch` not found
|
||||||
|
var parser: Parser = .{
|
||||||
|
.iter = .{ .bytes = "", .i = 0 },
|
||||||
|
};
|
||||||
|
try testing.expectEqualStrings("", parser.until(':'));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // substring starts at index 2 and goes upto `ch`
|
||||||
|
var parser: Parser = .{
|
||||||
|
.iter = .{ .bytes = "abc:1234", .i = 2 },
|
||||||
|
};
|
||||||
|
try testing.expectEqualStrings("c", parser.until(':'));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // substring starts at index 4 and goes upto the end - `ch` not found
|
||||||
|
var parser: Parser = .{
|
||||||
|
.iter = .{ .bytes = "abc1234", .i = 4 },
|
||||||
|
};
|
||||||
|
try testing.expectEqualStrings("234", parser.until(':'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "parser peek" {
|
||||||
|
{ // start iteration from the first index
|
||||||
|
var parser: Parser = .{
|
||||||
|
.iter = .{ .bytes = "hello world", .i = 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
try testing.expectEqual('h', parser.peek(0));
|
||||||
|
try testing.expectEqual('e', parser.peek(1));
|
||||||
|
try testing.expectEqual(' ', parser.peek(5));
|
||||||
|
try testing.expectEqual('d', parser.peek(10));
|
||||||
|
try testing.expectEqual(null, parser.peek(11));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // start iteration from the second last index
|
||||||
|
var parser: Parser = .{
|
||||||
|
.iter = .{ .bytes = "hello world!", .i = 10 },
|
||||||
|
};
|
||||||
|
|
||||||
|
try testing.expectEqual('d', parser.peek(0));
|
||||||
|
try testing.expectEqual('!', parser.peek(1));
|
||||||
|
try testing.expectEqual(null, parser.peek(5));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // start iteration beyond the length of the string
|
||||||
|
var parser: Parser = .{
|
||||||
|
.iter = .{ .bytes = "hello", .i = 5 },
|
||||||
|
};
|
||||||
|
|
||||||
|
try testing.expectEqual(null, parser.peek(0));
|
||||||
|
try testing.expectEqual(null, parser.peek(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // empty string
|
||||||
|
var parser: Parser = .{
|
||||||
|
.iter = .{ .bytes = "", .i = 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
try testing.expectEqual(null, parser.peek(0));
|
||||||
|
try testing.expectEqual(null, parser.peek(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "parser char" {
|
||||||
|
// character exists - iterator at 0
|
||||||
|
var parser: Parser = .{ .iter = .{ .bytes = "~~hello", .i = 0 } };
|
||||||
|
try testing.expectEqual('~', parser.char());
|
||||||
|
|
||||||
|
// character exists - iterator in the middle
|
||||||
|
parser = .{ .iter = .{ .bytes = "~~hello", .i = 3 } };
|
||||||
|
try testing.expectEqual('e', parser.char());
|
||||||
|
|
||||||
|
// character exists - iterator at the end
|
||||||
|
parser = .{ .iter = .{ .bytes = "~~hello", .i = 6 } };
|
||||||
|
try testing.expectEqual('o', parser.char());
|
||||||
|
|
||||||
|
// character doesn't exist - iterator beyond the length of the string
|
||||||
|
parser = .{ .iter = .{ .bytes = "~~hello", .i = 7 } };
|
||||||
|
try testing.expectEqual(null, parser.char());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "parser maybe" {
|
||||||
|
// character exists - iterator at 0
|
||||||
|
var parser: Parser = .{ .iter = .{ .bytes = "hello world", .i = 0 } };
|
||||||
|
try testing.expect(parser.maybe('h'));
|
||||||
|
|
||||||
|
// character exists - iterator at space
|
||||||
|
parser = .{ .iter = .{ .bytes = "hello world", .i = 5 } };
|
||||||
|
try testing.expect(parser.maybe(' '));
|
||||||
|
|
||||||
|
// character exists - iterator at the end
|
||||||
|
parser = .{ .iter = .{ .bytes = "hello world", .i = 10 } };
|
||||||
|
try testing.expect(parser.maybe('d'));
|
||||||
|
|
||||||
|
// character doesn't exist - iterator beyond the length of the string
|
||||||
|
parser = .{ .iter = .{ .bytes = "hello world", .i = 11 } };
|
||||||
|
try testing.expect(!parser.maybe('e'));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "parser number" {
|
||||||
|
// input is a single digit natural number - iterator at 0
|
||||||
|
var parser: Parser = .{ .iter = .{ .bytes = "7", .i = 0 } };
|
||||||
|
try testing.expect(7 == parser.number());
|
||||||
|
|
||||||
|
// input is a two digit natural number - iterator at 1
|
||||||
|
parser = .{ .iter = .{ .bytes = "29", .i = 1 } };
|
||||||
|
try testing.expect(9 == parser.number());
|
||||||
|
|
||||||
|
// input is a two digit natural number - iterator beyond the length of the string
|
||||||
|
parser = .{ .iter = .{ .bytes = "32", .i = 2 } };
|
||||||
|
try testing.expectEqual(null, parser.number());
|
||||||
|
|
||||||
|
// input is an integer
|
||||||
|
parser = .{ .iter = .{ .bytes = "0", .i = 0 } };
|
||||||
|
try testing.expect(0 == parser.number());
|
||||||
|
|
||||||
|
// input is a negative integer
|
||||||
|
parser = .{ .iter = .{ .bytes = "-2", .i = 0 } };
|
||||||
|
try testing.expectEqual(null, parser.number());
|
||||||
|
|
||||||
|
// input is a string
|
||||||
|
parser = .{ .iter = .{ .bytes = "no_number", .i = 2 } };
|
||||||
|
try testing.expectEqual(null, parser.number());
|
||||||
|
|
||||||
|
// input is a single character string
|
||||||
|
parser = .{ .iter = .{ .bytes = "n", .i = 0 } };
|
||||||
|
try testing.expectEqual(null, parser.number());
|
||||||
|
|
||||||
|
// input is an empty string
|
||||||
|
parser = .{ .iter = .{ .bytes = "", .i = 0 } };
|
||||||
|
try testing.expectEqual(null, parser.number());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "parser specifier" {
|
||||||
|
{ // input string is a digit; iterator at 0
|
||||||
|
const expected: Specifier = Specifier{ .number = 1 };
|
||||||
|
var parser: Parser = .{ .iter = .{ .bytes = "1", .i = 0 } };
|
||||||
|
|
||||||
|
const result = try parser.specifier();
|
||||||
|
try testing.expect(expected.number == result.number);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // input string is a two digit number; iterator at 0
|
||||||
|
const digit: Specifier = Specifier{ .number = 42 };
|
||||||
|
var parser: Parser = .{ .iter = .{ .bytes = "42", .i = 0 } };
|
||||||
|
|
||||||
|
const result = try parser.specifier();
|
||||||
|
try testing.expect(digit.number == result.number);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // input string is a two digit number digit; iterator at 1
|
||||||
|
const digit: Specifier = Specifier{ .number = 8 };
|
||||||
|
var parser: Parser = .{ .iter = .{ .bytes = "28", .i = 1 } };
|
||||||
|
|
||||||
|
const result = try parser.specifier();
|
||||||
|
try testing.expect(digit.number == result.number);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // input string is a two digit number with square brackets; iterator at 0
|
||||||
|
const digit: Specifier = Specifier{ .named = "15" };
|
||||||
|
var parser: Parser = .{ .iter = .{ .bytes = "[15]", .i = 0 } };
|
||||||
|
|
||||||
|
const result = try parser.specifier();
|
||||||
|
try testing.expectEqualStrings(digit.named, result.named);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // input string is not a number and contains square brackets; iterator at 0
|
||||||
|
const digit: Specifier = Specifier{ .named = "hello" };
|
||||||
|
var parser: Parser = .{ .iter = .{ .bytes = "[hello]", .i = 0 } };
|
||||||
|
|
||||||
|
const result = try parser.specifier();
|
||||||
|
try testing.expectEqualStrings(digit.named, result.named);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // input string is not a number and doesn't contain closing square bracket; iterator at 0
|
||||||
|
var parser: Parser = .{ .iter = .{ .bytes = "[hello", .i = 0 } };
|
||||||
|
|
||||||
|
const result = parser.specifier();
|
||||||
|
try testing.expectError(@field(anyerror, "Expected closing ]"), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // input string is not a number and doesn't contain closing square bracket; iterator at 2
|
||||||
|
var parser: Parser = .{ .iter = .{ .bytes = "[[[[hello", .i = 2 } };
|
||||||
|
|
||||||
|
const result = parser.specifier();
|
||||||
|
try testing.expectError(@field(anyerror, "Expected closing ]"), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // input string is not a number and contains unbalanced square brackets; iterator at 0
|
||||||
|
const digit: Specifier = Specifier{ .named = "[[hello" };
|
||||||
|
var parser: Parser = .{ .iter = .{ .bytes = "[[[hello]", .i = 0 } };
|
||||||
|
|
||||||
|
const result = try parser.specifier();
|
||||||
|
try testing.expectEqualStrings(digit.named, result.named);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // input string is not a number and contains unbalanced square brackets; iterator at 1
|
||||||
|
const digit: Specifier = Specifier{ .named = "[[hello" };
|
||||||
|
var parser: Parser = .{ .iter = .{ .bytes = "[[[[hello]]]]]", .i = 1 } };
|
||||||
|
|
||||||
|
const result = try parser.specifier();
|
||||||
|
try testing.expectEqualStrings(digit.named, result.named);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // input string is neither a digit nor a named argument
|
||||||
|
const char: Specifier = Specifier{ .none = {} };
|
||||||
|
var parser: Parser = .{ .iter = .{ .bytes = "hello", .i = 0 } };
|
||||||
|
|
||||||
|
const result = try parser.specifier();
|
||||||
|
try testing.expectEqual(char.none, result.none);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user