Skip to content

Commit 8a24793

Browse files
authored
Render custom assertion messages in logged Allure steps (via #18)
1 parent 89163ae commit 8a24793

3 files changed

Lines changed: 92 additions & 26 deletions

File tree

crates/allure-cargotest/tests/e2e.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,12 @@ fn generates_assertion_steps_by_default() {
615615
assert_eq!(json_string(passing, "status"), Some("passed"));
616616
assert!(passing.contains("\"name\":\"assert!(true)\",\"status\":\"passed\""));
617617
assert!(passing.contains("assert_eq!"));
618+
assert!(passing.contains(
619+
"\"name\":\"assert_eq!(user_id, 42): expected feature flag to be enabled for user_id=42\""
620+
));
621+
assert!(passing.contains(
622+
"\"name\":\"assert_eq!(is_valid, true): validation result was wrong for input [7, 13]\""
623+
));
618624
assert!(passing.contains("assert_ne!"));
619625
assert!(passing.contains("\"name\":\"step_assertions_are_nested\""));
620626
assert!(passing.contains("\"name\":\"assert_eq!(1 + 1, 2)\""));
@@ -624,7 +630,13 @@ fn generates_assertion_steps_by_default() {
624630
.expect("missing logs_failed_assertion_details result");
625631
assert_has_allure_result_fields(failing);
626632
assert_eq!(json_string(failing, "status"), Some("failed"));
627-
assert!(failing.contains("\"name\":\"assert_eq!"));
633+
assert_eq!(
634+
json_string(failing, "message"),
635+
Some("validation result was wrong for input [404, 500]")
636+
);
637+
assert!(failing.contains(
638+
r#""name":"assert_eq!(\"actual\", \"expected\"): validation result was wrong for input [404, 500]""#
639+
));
628640
assert!(failing.contains("\"status\":\"failed\""));
629641
assert!(failing.contains(r#""actual":"\"actual\"""#));
630642
assert!(failing.contains(r#""expected":"\"expected\"""#));

crates/allure-test-macros/src/lib.rs

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,6 +1194,42 @@ fn join_token_streams(streams: &[TokenStream]) -> String {
11941194
.join(", ")
11951195
}
11961196

1197+
#[derive(Clone)]
1198+
struct CustomAssertionMessage {
1199+
message_expr: String,
1200+
step_display_expr: String,
1201+
}
1202+
1203+
fn custom_assertion_message(parts: &[TokenStream], start: usize) -> Option<CustomAssertionMessage> {
1204+
if parts.len() <= start {
1205+
return None;
1206+
}
1207+
1208+
let custom = join_token_streams(&parts[start..]);
1209+
if custom.trim().is_empty() {
1210+
return None;
1211+
}
1212+
1213+
Some(CustomAssertionMessage {
1214+
message_expr: format!("format!(\"{{}}\", format_args!({custom}))"),
1215+
step_display_expr: format!("format_args!({custom})"),
1216+
})
1217+
}
1218+
1219+
fn assertion_step_name(base_name: &str, custom_message: Option<&CustomAssertionMessage>) -> String {
1220+
match custom_message {
1221+
Some(custom_message) => format!(
1222+
"format!(\"{{}}: {{}}\", {base_name}, {})",
1223+
custom_message.step_display_expr
1224+
),
1225+
None => base_name.to_string(),
1226+
}
1227+
}
1228+
1229+
fn assertion_step_name_from_message_var(base_name: &str) -> String {
1230+
format!("format!(\"{{}}: {{}}\", {base_name}, __allure_assert_message)")
1231+
}
1232+
11971233
fn generate_assert_code(kind: AssertMacroKind, args: TokenStream) -> Option<String> {
11981234
let parts = split_macro_args(args.clone());
11991235
let condition = parts.first()?.clone();
@@ -1202,32 +1238,30 @@ fn generate_assert_code(kind: AssertMacroKind, args: TokenStream) -> Option<Stri
12021238
}
12031239

12041240
let condition = condition.to_string();
1205-
let custom_message = if parts.len() > 1 {
1206-
let custom = join_token_streams(&parts[1..]);
1207-
if custom.trim().is_empty() {
1208-
None
1209-
} else {
1210-
Some(format!("format!(\"{{}}\", format_args!({custom}))"))
1211-
}
1212-
} else {
1213-
None
1214-
};
1241+
let custom_message = custom_assertion_message(&parts, 1);
12151242
let message = custom_message
1243+
.as_ref()
1244+
.map(|custom_message| custom_message.message_expr.clone())
12161245
.unwrap_or_else(|| format!("format!(\"assertion failed: {{}}\", stringify!({condition}))"));
12171246
let name = format!(
12181247
"concat!(\"{}!(\", stringify!({condition}), \")\")",
12191248
kind.macro_name()
12201249
);
1250+
let pass_name = assertion_step_name(&name, custom_message.as_ref());
1251+
let fail_name = custom_message
1252+
.as_ref()
1253+
.map(|_| assertion_step_name_from_message_var(&name))
1254+
.unwrap_or_else(|| name.clone());
12211255

12221256
let mut instrumented = String::new();
12231257
instrumented.push_str("if ");
12241258
instrumented.push_str(&condition);
12251259
instrumented.push_str(" { ::allure_cargotest::__private::record_assertion_pass(");
1226-
instrumented.push_str(&name);
1260+
instrumented.push_str(&pass_name);
12271261
instrumented.push_str("); } else { let __allure_assert_message = ");
12281262
instrumented.push_str(&message);
12291263
instrumented.push_str("; ::allure_cargotest::__private::fail_assertion(");
1230-
instrumented.push_str(&name);
1264+
instrumented.push_str(&fail_name);
12311265
instrumented.push_str(
12321266
", __allure_assert_message, Some(\"false\".to_string()), Some(\"true\".to_string())); }",
12331267
);
@@ -1257,20 +1291,20 @@ fn generate_assert_cmp_code(kind: AssertMacroKind, args: TokenStream) -> Option<
12571291
} else {
12581292
"format!(\"assertion `left == right` failed\\n left: `{:?}`,\\n right: `{:?}`\", __allure_assert_left, __allure_assert_right)"
12591293
};
1260-
let message = if parts.len() > 2 {
1261-
let custom = join_token_streams(&parts[2..]);
1262-
if custom.trim().is_empty() {
1263-
default_message.to_string()
1264-
} else {
1265-
format!("format!(\"{{}}\", format_args!({custom}))")
1266-
}
1267-
} else {
1268-
default_message.to_string()
1269-
};
1294+
let custom_message = custom_assertion_message(&parts, 2);
1295+
let message = custom_message
1296+
.as_ref()
1297+
.map(|custom_message| custom_message.message_expr.clone())
1298+
.unwrap_or_else(|| default_message.to_string());
12701299
let name = format!(
12711300
"concat!(\"{}!(\", stringify!({left}), \", \", stringify!({right}), \")\")",
12721301
kind.macro_name()
12731302
);
1303+
let pass_name = assertion_step_name(&name, custom_message.as_ref());
1304+
let fail_name = custom_message
1305+
.as_ref()
1306+
.map(|_| assertion_step_name_from_message_var(&name))
1307+
.unwrap_or_else(|| name.clone());
12741308

12751309
let mut instrumented = String::new();
12761310
instrumented.push_str("match (&(");
@@ -1284,11 +1318,11 @@ fn generate_assert_cmp_code(kind: AssertMacroKind, args: TokenStream) -> Option<
12841318
instrumented.push_str(
12851319
" *__allure_assert_right { ::allure_cargotest::__private::record_assertion_pass(",
12861320
);
1287-
instrumented.push_str(&name);
1321+
instrumented.push_str(&pass_name);
12881322
instrumented.push_str("); } else { let __allure_assert_message = ");
12891323
instrumented.push_str(&message);
12901324
instrumented.push_str("; ::allure_cargotest::__private::fail_assertion(");
1291-
instrumented.push_str(&name);
1325+
instrumented.push_str(&fail_name);
12921326
instrumented.push_str(", __allure_assert_message, Some(format!(\"{:?}\", __allure_assert_left)), Some(format!(\"{:?}\", __allure_assert_right))); } } }");
12931327

12941328
Some(runtime_assert_code(

smokes/allure-cargotest/tests/assertions.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,22 @@ fn step_assertions_are_nested() {
1515
fn logs_passing_assertions() {
1616
allure.description("Verifies passing standard assertions are emitted as reviewable Allure steps.");
1717
allure.log_step("run passing assertion matrix");
18+
let user_id = 42;
19+
let input = [7, 13];
20+
let is_valid = true;
1821
assert!(true);
1922
assert_eq!("actual", "actual");
23+
assert_eq!(
24+
user_id,
25+
42,
26+
"expected feature flag to be enabled for user_id={user_id}"
27+
);
28+
assert_eq!(
29+
is_valid,
30+
true,
31+
"validation result was wrong for input {:?}",
32+
input
33+
);
2034
assert_ne!("left", "right");
2135

2236
helper_assertions_are_logged();
@@ -28,5 +42,11 @@ fn logs_passing_assertions() {
2842
fn logs_failed_assertion_details() {
2943
allure.description("Verifies a failed standard assertion records actual and expected values in status details.");
3044
allure.log_step("run assertion that should fail with captured details");
31-
assert_eq!("actual", "expected");
45+
let input = [404, 500];
46+
assert_eq!(
47+
"actual",
48+
"expected",
49+
"validation result was wrong for input {:?}",
50+
input
51+
);
3252
}

0 commit comments

Comments
 (0)