mirror of
https://github.com/vercel-labs/fx.git
synced 2026-10-28 10:15:17 +08:00
Encode inline fuzz seeds the way the tests read them
A fuzz test reads its input through std.testing.Smith, which reads a slice as a little-endian u32 length and then that many bytes. The inline seeds of the older fuzz tests were plain strings, so each lost its first four bytes to the length: "one" replayed as an empty input, and "split every field" read "spli" as a length. The fx tests now wrap their seeds in fuzz_seed.slices, which writes that length first. The session manager imports nothing from fx, so its two targets keep their seeds as saved inputs in tests/fuzz/corpus.
This commit is contained in:
23 files changed
+78
-38
No files matched your search
+2
-2
@@ -111,9 +111,9 @@ When the search finds a failure, Zig 0.17 prints `error: test '...'` but still e
|
||||
|
||||
The Fuzz workflow fuzzes each target on `main` every night for about 20 minutes, and for two minutes on a pull request that changes the fuzzing setup. When the nightly run finds a failure, it uploads the failing input as an artifact and opens an issue titled `Nightly fuzz failure: <target>`, or comments on that issue if it is already open. To fix the failure, copy the input into `tests/fuzz/corpus/<target>/` and run `zig build fuzz -Dfuzz-target=<target>` to reproduce it. That build uses Debug by default, which adds allocation stack traces to leak reports. Keep the input file in the fix's pull request, so `zig build test` replays it on every pull request after that.
|
||||
|
||||
A saved input holds the values the test reads from its `std.testing.Smith`, in order. For example, a test that calls `smith.slice` reads a 4-byte little-endian length and then that many bytes. Inputs that the fuzzer saves are already in this form.
|
||||
A saved input holds the values the test reads from its `std.testing.Smith`, in order. For example, a test that calls `smith.slice` reads a 4-byte little-endian length and then that many bytes. Inputs that the fuzzer saves are already in this form. Inline seeds go through `@import("fuzz_seed").slices`, which writes each one in this form for a test whose first read is `smith.slice`. A seed written as a plain string would lose its first four bytes to the length.
|
||||
|
||||
To add a target, write the fuzz test in the file it covers and add an entry to `tests/fuzz/targets.json`. For a target outside the session manager, also import its file in `src/fuzz_targets.zig`. Pass the saved inputs to the test with `.corpus = &(.{ <seeds> } ++ @import("fuzz_corpus").<target>.*)`, or with `@import("build_options").fuzz_corpus_<target>` in the session manager. Set `iterations` so that one round of `--fuzz` takes about 30 seconds on a developer machine. `scripts/tests/test_fuzz_nightly.py` fails when an entry names a test that doesn't exist or that `zig build fuzz` can't reach. The MCP engine in `src/mcp/` imports only the standard library, so its targets live in `src/core/mcp_host/wire_tests.zig`. A file that holds only tests, like that one, is also imported from the test block in `src/main.zig`.
|
||||
To add a target, write the fuzz test in the file it covers and add an entry to `tests/fuzz/targets.json`. For a target outside the session manager, also import its file in `src/fuzz_targets.zig`. Pass the seeds and saved inputs to the test with `.corpus = &(@import("fuzz_seed").slices(.{ <seeds> }) ++ @import("fuzz_corpus").<target>.*)`. The session manager imports nothing from fx, so its targets keep their seeds as files in `tests/fuzz/corpus/<target>/` and pass `.corpus = &(.{""} ++ @import("build_options").fuzz_corpus_<target>.*)`. Set `iterations` so that one round of `--fuzz` takes about 30 seconds on a developer machine. `scripts/tests/test_fuzz_nightly.py` fails when an entry names a test that doesn't exist or that `zig build fuzz` can't reach. The MCP engine in `src/mcp/` imports only the standard library, so its targets live in `src/core/mcp_host/wire_tests.zig`. A file that holds only tests, like that one, is also imported from the test block in `src/main.zig`.
|
||||
|
||||
### Find data races
|
||||
|
||||
|
||||
@@ -60,6 +60,12 @@ pub fn build(b: *std.Build) void {
|
||||
|
||||
const fuzz_corpora = readFuzzCorpora(b);
|
||||
const fuzz_corpus = addFuzzCorpusModule(b, fuzz_corpora);
|
||||
// Encodes the fuzz tests' inline seeds the way they read them.
|
||||
const fuzz_seed = b.createModule(.{
|
||||
.root_source_file = b.path("src/fuzz_seed.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "fx",
|
||||
@@ -81,6 +87,7 @@ pub fn build(b: *std.Build) void {
|
||||
});
|
||||
exe.root_module.addImport("build_options", build_options.createModule());
|
||||
exe.root_module.addImport("fuzz_corpus", fuzz_corpus);
|
||||
exe.root_module.addImport("fuzz_seed", fuzz_seed);
|
||||
const session_manager = addSessionManager(b, exe.root_module, target, optimize, null, fuzz_corpora);
|
||||
session_manager.sanitize_thread = sanitize_thread;
|
||||
|
||||
@@ -124,6 +131,7 @@ pub fn build(b: *std.Build) void {
|
||||
test_step.dependOn(&run_exe_tests.step);
|
||||
test_step.dependOn(&run_session_manager_tests.step);
|
||||
test_step.dependOn(&run_session_manager_hook_tests.step);
|
||||
test_step.dependOn(&b.addRunArtifact(b.addTest(.{ .root_module = fuzz_seed })).step);
|
||||
|
||||
const fuzz_step = b.step(
|
||||
"fuzz",
|
||||
@@ -142,6 +150,7 @@ pub fn build(b: *std.Build) void {
|
||||
});
|
||||
fuzz_root.addImport("build_options", build_options.createModule());
|
||||
fuzz_root.addImport("fuzz_corpus", fuzz_corpus);
|
||||
fuzz_root.addImport("fuzz_seed", fuzz_seed);
|
||||
fuzz_root.addImport("session_manager", session_manager);
|
||||
fuzz_root.addImport("test_paths", test_paths_module);
|
||||
addFuzzStep(b, fuzz_step, fuzz_corpora, fuzz_target, .{
|
||||
|
||||
@@ -560,12 +560,12 @@ fn fuzzParse(_: void, smith: *std.testing.Smith) !void {
|
||||
|
||||
test "ACP MCP parser handles fuzzed request bytes" {
|
||||
try std.testing.fuzz({}, fuzzParse, .{
|
||||
.corpus = &(.{
|
||||
.corpus = &(@import("fuzz_seed").slices(.{
|
||||
"",
|
||||
"{}",
|
||||
"{\"mcpServers\":[]}",
|
||||
"{\"mcpServers\":[{\"name\":\"fixture\",\"command\":\"/bin/echo\",\"args\":[],\"env\":[]}]}",
|
||||
"{\"mcpServers\":[{\"type\":\"http\",\"name\":\"fixture\",\"url\":\"http://localhost:4321/mcp\",\"headers\":[]}]}",
|
||||
} ++ @import("fuzz_corpus").acp_mcp_servers.*),
|
||||
}) ++ @import("fuzz_corpus").acp_mcp_servers.*),
|
||||
});
|
||||
}
|
||||
@@ -1017,11 +1017,11 @@ fn fuzz_vision_json(_: void, smith: *std.testing.Smith) !void {
|
||||
|
||||
test "Vision JSON parsers tolerate arbitrary bounded bytes" {
|
||||
try std.testing.fuzz({}, fuzz_vision_json, .{
|
||||
.corpus = &(.{
|
||||
.corpus = &(@import("fuzz_seed").slices(.{
|
||||
"{\"image_ids\":[1],\"focus\":\"inspect\"}",
|
||||
"{\"images\":[{\"image_id\":1,\"status\":\"failed\",\"error\":\"vision_unavailable\"}]}",
|
||||
"{",
|
||||
} ++ @import("fuzz_corpus").vision_json.*),
|
||||
}) ++ @import("fuzz_corpus").vision_json.*),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -544,7 +544,7 @@ test "encoded image dimensions agree with raw headers at every truncation" {
|
||||
|
||||
test "image dimension parsing stays bounded on arbitrary bytes" {
|
||||
try std.testing.fuzz({}, fuzzImageDimensions, .{
|
||||
.corpus = &(.{
|
||||
.corpus = &(@import("fuzz_seed").slices(.{
|
||||
&testPngHeader(3420, 2224),
|
||||
&testJpeg(2001, 1),
|
||||
&testGif(1, 1),
|
||||
@@ -556,7 +556,7 @@ test "image dimension parsing stays bounded on arbitrary bytes" {
|
||||
"\x89PNG\r\n\x1a\n\x00\x00\x00\x00IHDR\xff\xff\xff\xff\xff\xff\xff\xff",
|
||||
// RIFF header naming WebP with no chunk.
|
||||
"RIFF\x00\x00\x00\x00WEBP",
|
||||
} ++ @import("fuzz_corpus").image_dimensions.*),
|
||||
}) ++ @import("fuzz_corpus").image_dimensions.*),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -2143,12 +2143,12 @@ fn fuzzElicitationJson(_: void, smith: *std.testing.Smith) !void {
|
||||
|
||||
test "elicitation request and response parsers stay bounded under fuzzed bytes" {
|
||||
try std.testing.fuzz({}, fuzzElicitationJson, .{
|
||||
.corpus = &(.{
|
||||
.corpus = &(@import("fuzz_seed").slices(.{
|
||||
"{}",
|
||||
"{\"mode\":\"form\",\"requestedSchema\":{}}",
|
||||
"{\"action\":\"accept\",\"content\":{}}",
|
||||
"{\"mode\":\"url\",\"url\":\"https://example.test\"}",
|
||||
"{\"jsonrpc\":\"2.0\",\"method\":\"notifications/elicitation/complete\",\"params\":{\"elicitationId\":\"id\"}}",
|
||||
} ++ @import("fuzz_corpus").mcp_elicitation.*),
|
||||
}) ++ @import("fuzz_corpus").mcp_elicitation.*),
|
||||
});
|
||||
}
|
||||
@@ -5951,7 +5951,7 @@ test "an old session's usage field is skipped in its place, and the rest loads"
|
||||
}
|
||||
|
||||
test "durable session optional fields handle fuzzed ownership paths" {
|
||||
try std.testing.fuzz({}, fuzzDurableSessionOptionalFields, .{ .corpus = &(.{
|
||||
try std.testing.fuzz({}, fuzzDurableSessionOptionalFields, .{ .corpus = &(@import("fuzz_seed").slices(.{
|
||||
"{\"id\":\"session\",\"origin_workspace_root\":\"/tmp/origin\",\"workspace_root\":\"/tmp/current\",\"created_at_ms\":1,\"updated_at_ms\":1,\"conversation_language\":\"en\",\"preferences\":{\"model\":\"test/model\",\"effort\":\"auto\",\"fast_mode\":false},\"history\":[],\"total_input_tokens\":0,\"total_output_tokens\":0}",
|
||||
"{\"id\":\"session\",\"origin_workspace_root\":\"/tmp/origin\",\"workspace_root\":\"/tmp/current\",\"created_at_ms\":1,\"updated_at_ms\":1,\"conversation_language\":\"en\",\"preferences\":{\"model\":\"test/model\",\"effort\":\"auto\",\"fast_mode\":false},\"history\":[],\"total_input_tokens\":0,\"total_output_tokens\":0,\"context_history_start\":0,\"last_subagent_work_id\":\"work\"}",
|
||||
"{\"id\":\"session\",\"origin_workspace_root\":\"/tmp/origin\",\"workspace_root\":\"/tmp/current\",\"created_at_ms\":1,\"updated_at_ms\":1,\"conversation_language\":\"en\",\"preferences\":{\"model\":\"test/model\",\"effort\":\"auto\",\"fast_mode\":false},\"history\":[],\"total_input_tokens\":0,\"total_output_tokens\":0,\"last_subagent_work_id\":\"work\",\"context_history_start\":0}",
|
||||
@@ -5960,17 +5960,17 @@ test "durable session optional fields handle fuzzed ownership paths" {
|
||||
"{\"last_subagent_work_id\":null}",
|
||||
"{\"usage\":null,\"last_subagent_work_id\":\"work\"}",
|
||||
"{\"last_subagent_work_id\":\"work\",\"usage\":null}",
|
||||
} ++ @import("fuzz_corpus").session_optional_fields.*) });
|
||||
}) ++ @import("fuzz_corpus").session_optional_fields.*) });
|
||||
}
|
||||
|
||||
test "per-turn work provenance parser handles fuzzed ownership paths" {
|
||||
try std.testing.fuzz({}, fuzzWorkProvenanceHistoryTurn, .{ .corpus = &(.{
|
||||
try std.testing.fuzz({}, fuzzWorkProvenanceHistoryTurn, .{ .corpus = &(@import("fuzz_seed").slices(.{
|
||||
"{\"kind\":\"assistant\",\"user\":{\"text\":\"prompt\",\"images\":[],\"work_id\":\"work-1\"},\"assistant\":\"reply\",\"execution\":{\"schema_version\":3,\"tool_steps\":[],\"files\":[]}}",
|
||||
"{\"kind\":\"assistant\",\"user\":{\"text\":\"prompt\",\"images\":[]},\"assistant\":\"reply\",\"execution\":{\"schema_version\":3,\"tool_steps\":[],\"files\":[]}}",
|
||||
"{\"kind\":\"assistant\",\"user\":{\"text\":\"prompt\",\"images\":[],\"work_id\":\"\"}}",
|
||||
"",
|
||||
"{}",
|
||||
} ++ @import("fuzz_corpus").session_work_provenance.*) });
|
||||
}) ++ @import("fuzz_corpus").session_work_provenance.*) });
|
||||
}
|
||||
|
||||
fn fuzzWorkProvenanceHistoryTurn(_: void, smith: *std.testing.Smith) !void {
|
||||
|
||||
@@ -3171,12 +3171,12 @@ test "conversation frame rejects an oversized diff content handle" {
|
||||
|
||||
test "conversation frame decoder stays bounded under fuzzed bytes" {
|
||||
try std.testing.fuzz({}, fuzzConversationFrame, .{
|
||||
.corpus = &(.{
|
||||
.corpus = &(@import("fuzz_seed").slices(.{
|
||||
"",
|
||||
"{}\n",
|
||||
"{\"schema_version\":1}\n",
|
||||
"{\"schema_version\":1,\"seq\":1,\"timestamp_ms\":0,\"event\":{\"assistant\":{\"text\":\"ok\"}}}\n",
|
||||
} ++ @import("fuzz_corpus").session_conversation_frame.*),
|
||||
}) ++ @import("fuzz_corpus").session_conversation_frame.*),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -773,10 +773,7 @@ test "any prefix of a valid log scans to its last complete line" {
|
||||
}
|
||||
|
||||
test "scanning never panics on arbitrary bytes" {
|
||||
try testing.fuzz({}, fuzzScan, .{ .corpus = &(.{
|
||||
"{\"v\":1,\"seq\":1,\"ts\":0,\"kind\":\"item\",\"crc\":\"00000000\"}\n",
|
||||
"\n\n\n",
|
||||
} ++ @import("build_options").fuzz_corpus_session_log_scan.*) });
|
||||
try testing.fuzz({}, fuzzScan, .{ .corpus = &(.{""} ++ @import("build_options").fuzz_corpus_session_log_scan.*) });
|
||||
}
|
||||
|
||||
fn fuzzScan(_: void, smith: *testing.Smith) anyerror!void {
|
||||
|
||||
@@ -806,10 +806,7 @@ test "ids follow v1's alphabet and avoid the reserved names" {
|
||||
}
|
||||
|
||||
test "header parsing never panics on arbitrary bytes" {
|
||||
try testing.fuzz({}, fuzzHeader, .{ .corpus = &(.{
|
||||
"{\"v\":1,\"seq\":1,\"ts\":0,\"kind\":\"item\"",
|
||||
"{\"v\":99999999999,\"seq\":1",
|
||||
} ++ @import("build_options").fuzz_corpus_session_schema_header.*) });
|
||||
try testing.fuzz({}, fuzzHeader, .{ .corpus = &(.{""} ++ @import("build_options").fuzz_corpus_session_schema_header.*) });
|
||||
}
|
||||
|
||||
fn fuzzHeader(_: void, smith: *testing.Smith) anyerror!void {
|
||||
|
||||
@@ -828,14 +828,14 @@ test "display unit clipping preserves sequence boundaries" {
|
||||
|
||||
test "fuzz display unit boundaries" {
|
||||
try std.testing.fuzz({}, fuzzDisplayUnitBoundaries, .{
|
||||
.corpus = &(.{
|
||||
.corpus = &(@import("fuzz_seed").slices(.{
|
||||
"",
|
||||
"plain text",
|
||||
"\xff\xf0\x28\x8c\x28",
|
||||
"\u{2600}\u{FE0E}\u{2600}\u{FE0F}",
|
||||
"\u{1F44D}\u{1F3FD}\u{1F1FA}\u{1F1F8}",
|
||||
"#\u{FE0F}\u{20E3}\u{1F469}\u{200D}\u{1F4BB}",
|
||||
} ++ @import("fuzz_corpus").display_width.*),
|
||||
}) ++ @import("fuzz_corpus").display_width.*),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3262,13 +3262,13 @@ fn fuzzToolArgumentDiagnostic(_: void, smith: *std.testing.Smith) anyerror!void
|
||||
|
||||
test "fuzz tool argument diagnostic" {
|
||||
try std.testing.fuzz({}, fuzzToolArgumentDiagnostic, .{
|
||||
.corpus = &(.{
|
||||
.corpus = &(@import("fuzz_seed").slices(.{
|
||||
"{\"request\":{\"task\":\"cut",
|
||||
"{\"a\":1,}",
|
||||
"{\"a\":1,\"a\":2}",
|
||||
"{\"t\":\"\xc3\xa9\xe2\x82",
|
||||
"\xff\x00{",
|
||||
} ++ @import("fuzz_corpus").tool_argument_diagnostic.*),
|
||||
}) ++ @import("fuzz_corpus").tool_argument_diagnostic.*),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1061,14 +1061,14 @@ test "parseSkillFile rejects indented continuations for recognized metadata" {
|
||||
|
||||
test "parseSkillFile keeps fuzzed borrowed slices inside the input" {
|
||||
try std.testing.fuzz({}, fuzzParseSkillFile, .{
|
||||
.corpus = &(.{
|
||||
.corpus = &(@import("fuzz_seed").slices(.{
|
||||
"",
|
||||
"plain body",
|
||||
"---\nname: valid\n---\nbody",
|
||||
"---\r\nname: \"valid\"\r\n---\r\nbody",
|
||||
"---\nname: quoted\ndescription: 'single line'\n---\nbody",
|
||||
"---\nname: block\ndescription: >-\n first line\n second line\n---\nbody",
|
||||
} ++ @import("fuzz_corpus").skill_file.*),
|
||||
}) ++ @import("fuzz_corpus").skill_file.*),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -113,11 +113,11 @@ test "skill display name parsing stays bounded" {
|
||||
try std.testing.expect(name.len <= buffer.len);
|
||||
try std.testing.expect(skill_contract.invalidSkillNameCause(name) == null);
|
||||
}
|
||||
}.check, .{ .corpus = &(.{
|
||||
}.check, .{ .corpus = &(@import("fuzz_seed").slices(.{
|
||||
content_name_prefix ++ "workflow\" location=\"/skills/workflow\">",
|
||||
discovery_model_notice ++ content_name_prefix ++ "name&value\" resource=\"SKILL.md\">",
|
||||
content_name_prefix ++ "bad&unknown;\" location=\"/skills/workflow\">",
|
||||
} ++ @import("fuzz_corpus").skill_display_name.*) });
|
||||
}) ++ @import("fuzz_corpus").skill_display_name.*) });
|
||||
}
|
||||
|
||||
/// Borrows a previously discovered skill inventory for one invocation.
|
||||
|
||||
@@ -707,11 +707,11 @@ fn fuzzCommandOutputContent(_: void, smith: *std.testing.Smith) anyerror!void {
|
||||
|
||||
test "fuzz command output content" {
|
||||
try std.testing.fuzz({}, fuzzCommandOutputContent, .{
|
||||
.corpus = &(.{
|
||||
.corpus = &(@import("fuzz_seed").slices(.{
|
||||
"progress\roverwrite\n",
|
||||
"\x1b[31mred\x1b[0m\n",
|
||||
"exit_code=0\n<stdout>\none\n</stdout>\n",
|
||||
"\xff\x00\xe2\x82",
|
||||
} ++ @import("fuzz_corpus").command_output_content.*),
|
||||
}) ++ @import("fuzz_corpus").command_output_content.*),
|
||||
});
|
||||
}
|
||||
@@ -4238,7 +4238,7 @@ test "deinit cancels and joins one loader while suppressing queued refresh" {
|
||||
|
||||
test "file index raw-list and Unicode query bytes remain bounded" {
|
||||
try std.testing.fuzz({}, fuzzRawListAndQuery, .{
|
||||
.corpus = &(.{
|
||||
.corpus = &(@import("fuzz_seed").slices(.{
|
||||
"safe.txt\x00ärger",
|
||||
"escape-\x1b[2J.txt\x00\xff",
|
||||
"Ärger-file.txt\x00ärger",
|
||||
@@ -4247,7 +4247,7 @@ test "file index raw-list and Unicode query bytes remain bounded" {
|
||||
"docs/Cafe\u{0301}.txt\x00e\u{0301}",
|
||||
"src/axaya.zig\x00aaa",
|
||||
"truncated.txt\x00\xc3",
|
||||
} ++ @import("fuzz_corpus").file_index.*),
|
||||
}) ++ @import("fuzz_corpus").file_index.*),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
//! Inline seeds for fuzz tests, in the form the tests read them.
|
||||
//!
|
||||
//! A fuzz test reads its input through `std.testing.Smith`, which reads a
|
||||
//! `smith.slice` as a little-endian u32 length and then that many bytes. A
|
||||
//! seed written as a plain string loses its first four bytes to the length,
|
||||
//! so `"one"` replays as an empty slice. `build.zig` makes this file the
|
||||
//! `fuzz_seed` module for fx's tests. The session manager imports nothing
|
||||
//! from fx, so its targets keep their seeds in `tests/fuzz/corpus/`.
|
||||
const std = @import("std");
|
||||
|
||||
/// Encodes each of `seeds`, a tuple of byte strings, as the input that makes
|
||||
/// a fuzz test's first `smith.slice` return it.
|
||||
pub fn slices(comptime seeds: anytype) [seeds.len][]const u8 {
|
||||
return comptime encoded: {
|
||||
var inputs: [seeds.len][]const u8 = undefined;
|
||||
for (&inputs, 0..) |*input, i| input.* = slice(seeds[i]);
|
||||
break :encoded inputs;
|
||||
};
|
||||
}
|
||||
|
||||
fn slice(comptime bytes: []const u8) []const u8 {
|
||||
return comptime encoded: {
|
||||
var len: [4]u8 = undefined;
|
||||
std.mem.writeInt(u32, &len, bytes.len, .little);
|
||||
const input = len ++ bytes[0..bytes.len].*;
|
||||
break :encoded &input;
|
||||
};
|
||||
}
|
||||
|
||||
test "a seed reads back through the fuzz input reader" {
|
||||
const inputs = slices(.{ "", "one", "split every field" });
|
||||
for (inputs, [_][]const u8{ "", "one", "split every field" }) |input, seed| {
|
||||
var smith: std.testing.Smith = .{ .in = input };
|
||||
var buffer: [32]u8 = undefined;
|
||||
try std.testing.expectEqualStrings(seed, buffer[0..smith.slice(&buffer)]);
|
||||
}
|
||||
}
|
||||
@@ -2167,7 +2167,7 @@ test "Responses text finalization fuzzes chunking and capture boundaries" {
|
||||
try stream.finish(buffer[0 .. len + separator.len + 4]);
|
||||
}
|
||||
};
|
||||
try std.testing.fuzz({}, Probe.run, .{ .corpus = &(.{ "", "a", "two chunks", "capture limit is not receipt progress" } ++ @import("fuzz_corpus").responses_text.*) });
|
||||
try std.testing.fuzz({}, Probe.run, .{ .corpus = &(@import("fuzz_seed").slices(.{ "", "a", "two chunks", "capture limit is not receipt progress" }) ++ @import("fuzz_corpus").responses_text.*) });
|
||||
}
|
||||
|
||||
test "Responses captures assistant commentary phase" {
|
||||
|
||||
+1
-1
@@ -263,7 +263,7 @@ test "provider framing fuzzes chunk-invariant event data" {
|
||||
try std.testing.expectEqual(null, try reader.next(alloc, &source.interface, &cancelled));
|
||||
}
|
||||
};
|
||||
try std.testing.fuzz({}, Probe.run, .{ .corpus = &(.{ "", "one", "split every field" } ++ @import("fuzz_corpus").sse_framing.*) });
|
||||
try std.testing.fuzz({}, Probe.run, .{ .corpus = &(@import("fuzz_seed").slices(.{ "", "one", "split every field" }) ++ @import("fuzz_corpus").sse_framing.*) });
|
||||
}
|
||||
|
||||
fn check_allocations(alloc: std.mem.Allocator) !void {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in new issue
Block a user