Commit Diff


commit - ade20e173499fe07ed4a9826662db533fc795456
commit + 2440fa356713a6a5e24841131db5ecafa143a0ed
blob - 284b995e0acc3f061f32013d5d482c128af327ce
blob + 1090a5bf0d5dc1f8c9e76e79baba43a936f5db9a
--- regress/artifact_result/artifact_result_test.c
+++ regress/artifact_result/artifact_result_test.c
@@ -224,6 +224,83 @@ test_boundary_selection(void)
 }
 
 static void
+test_exact_inline_boundaries(void)
+{
+	static const struct {
+		const char *name;
+		u_char byte;
+		const char *encoding;
+		size_t encoded_step;
+	} shapes[] = {
+		{ "printable", 'x', "utf-8", 1 },
+		{ "escape-heavy", '\1', "utf-8", 6 },
+		{ "NUL", '\0', "utf-8", 6 },
+		{ "invalid UTF-8/base64", 0xff, "base64", 4 }
+	};
+	struct artifact_result in;
+	struct json j;
+	struct buf out;
+	char *encoding;
+	u_char *raw;
+	size_t elen, hi, i, lo, mid;
+	int root;
+
+	raw = malloc(ARTIFACT_RESULT_MAX + 1);
+	CHECK(raw != NULL);
+	if (raw == NULL)
+		return;
+	buf_init(&out);
+	for (i = 0; i < sizeof(shapes) / sizeof(shapes[0]); i++) {
+		memset(raw, shapes[i].byte, ARTIFACT_RESULT_MAX + 1);
+		lo = 0;
+		hi = ARTIFACT_RESULT_MAX + 1;
+		while (lo + 1 < hi) {
+			mid = lo + (hi - lo) / 2;
+			if (artifact_result_inline_fits(raw, mid))
+				lo = mid;
+			else
+				hi = mid;
+		}
+		CHECK(lo != 0 && artifact_result_inline_fits(raw, lo));
+		CHECK(!artifact_result_inline_fits(raw, lo + 1));
+
+		memset(&in, 0, sizeof(in));
+		in.raw = raw;
+		in.raw_len = lo;
+		in.observed_bytes = lo;
+		in.retained_bytes = lo;
+		in.termination = ARTIFACT_TERM_EXIT;
+		CHECK(artifact_result_build(&out, &in) == 0 &&
+		    out.len <= ARTIFACT_RESULT_MAX &&
+		    ARTIFACT_RESULT_MAX - out.len < shapes[i].encoded_step);
+		CHECK(json_parse(&j, out.data, out.len, 0) == 0);
+		root = json_root(&j);
+		CHECK(json_get_bool(&j, json_obj_get(&j, root,
+		    "preview_abbreviated")) == 0);
+		encoding = string_field(&j, root, "preview_encoding", &elen);
+		CHECK(encoding != NULL && elen == strlen(shapes[i].encoding) &&
+		    memcmp(encoding, shapes[i].encoding, elen) == 0);
+		free(encoding);
+		json_done(&j);
+
+		in.raw_len = lo + 1;
+		in.observed_bytes = lo + 1;
+		in.retained_bytes = lo + 1;
+		in.id = good_id;
+		CHECK(artifact_result_build(&out, &in) == 0 &&
+		    out.len <= ARTIFACT_RESULT_MAX);
+		CHECK(json_parse(&j, out.data, out.len, 0) == 0);
+		root = json_root(&j);
+		CHECK(json_get_bool(&j, json_obj_get(&j, root,
+		    "preview_abbreviated")) == 1);
+		json_done(&j);
+		(void)shapes[i].name;
+	}
+	buf_free(&out);
+	free(raw);
+}
+
+static void
 test_error_metadata_is_not_spoofable(void)
 {
 	static const char detail[] = "spawn failed before capture";
@@ -462,6 +539,7 @@ main(void)
 	test_encoded_budgets_and_id();
 	test_binary_base64();
 	test_boundary_selection();
+	test_exact_inline_boundaries();
 	test_error_metadata_is_not_spoofable();
 	test_json_integer_range();
 	test_empty_streaming_capture_is_inline();