aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/root.zig
blob: 782f0783a3c73f47e68a7a30d036399e7f79dfb6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
const std = @import("std");
pub const jq = @import("./jq.zig");
pub const jv = @import("./jv.zig");

pub fn run(allocator: std.mem.Allocator, input: []const u8, query: []const u8) ![]const u8 {
    const parsed = try jv.parse(allocator, input);
    defer parsed.deinit();
    const json = parsed.value;

    var runtime = try jq.Runtime.init(allocator);
    defer runtime.deinit();
    try runtime.compileFromSlice(query);
    try runtime.start(json);
    const result = try runtime.next() orelse return error.NoResult;
    const output = try jv.stringify(allocator, result);
    return output;
}

fn testRun(expected: []const u8, input: []const u8, query: []const u8) !void {
    try testRunMultiple(&.{expected}, input, query);
}

fn testRunMultiple(expected: []const []const u8, input: []const u8, query: []const u8) !void {
    const allocator = std.testing.allocator;

    const parsed = try jv.parse(allocator, input);
    defer parsed.deinit();
    const json = parsed.value;

    var runtime = try jq.Runtime.init(allocator);
    defer runtime.deinit();
    try runtime.compileFromSlice(query);
    try runtime.start(json);

    for (expected) |ex| {
        const result_value = try runtime.next() orelse return error.NoResult;
        const result = try jv.stringify(allocator, result_value);
        defer allocator.free(result);
        try std.testing.expectEqualStrings(ex, result);
    }

    try std.testing.expectEqual(null, try runtime.next());
}

test "identity filter" {
    try testRun("null", "null", ".");
    try testRun("false", "false", ".");
    try testRun("true", "true", ".");
    try testRun("123", "123", ".");
    try testRun("3.1415", "3.1415", ".");
    try testRun("[]", "[]", ".");
    try testRun("{}", "{}", ".");
    try testRun("[1,2,3]", "[1,2,3]", ".");
    try testRun("{\"a\":123}", "{\"a\":123}", ".");
}

test "array index filter" {
    try testRun("null", "[]", ".[0]");
    try testRun("1", "[1,2,3]", ".[0]");
    try testRun("null", "[1,2,3]", ".[5]");
    try testRun("11", "[0,1,2,3,4,5,6,7,8,9,10,11,12]", ".[11]");
    try testRun("100",
        \\[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,
        \\ 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
        \\ 41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,
        \\ 61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,
        \\ 81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100]
    , ".[100]");
}

test "object key filter" {
    try testRun("123", "{\"a\":123}", ".a");
    try testRun("null", "{\"a\":123}", ".b");
    try testRun("\"hello\"", "{\"foo\":\"hello\"}", ".foo");
    try testRun("[1,2,3]", "{\"arr\":[1,2,3]}", ".arr");
    try testRun("{\"bar\":true}", "{\"foo\":{\"bar\":true}}", ".foo");
}

test "arithmetic operations" {
    try testRun("579", "null", "123 + 456");
    try testRun("35", "{\"a\":12,\"b\":23}", ".a + .b");
    try testRun("12", "[1,2,3]", ".[1] + 10");
    try testRun("6", "null", "1 + 2 + 3");

    try testRun("333", "null", "456 - 123");
    try testRun("-11", "{\"a\":12,\"b\":23}", ".a - .b");
    try testRun("-8", "[1,2,3]", ".[1] - 10");
    try testRun("-4", "null", "1 - 2 - 3");

    try testRun("56088", "null", "123 * 456");
    try testRun("276", "{\"a\":12,\"b\":23}", ".a * .b");
    try testRun("20", "[1,2,3]", ".[1] * 10");
    try testRun("6", "null", "1 * 2 * 3");

    try testRun("3", "null", "456 / 123");
    try testRun("0", "{\"a\":12,\"b\":23}", ".a / .b");
    try testRun("5", "[10,20,30]", ".[1] / 4");
    try testRun("2", "null", "12 / 2 / 3");

    try testRun("87", "null", "456 % 123");
    try testRun("12", "{\"a\":12,\"b\":23}", ".a % .b");
    try testRun("0", "[1,2,3]", ".[1] % 2");
    try testRun("0", "null", "12 % 2 % 3");
}

test "pipe operator" {
    try testRun("123", "{\"a\":{\"b\":123}}", ".a | .b");
    try testRun("584", "null", "123 + 456 | . + 5");
    try testRun("10", "null", "1 | . + 2 | . + 3 | . | 4 + .");
}

test "comma operator" {
    try testRunMultiple(&.{ "12", "34", "56" }, "{\"a\":12,\"b\":34,\"c\":56}", ".a,.b,.c");
}