summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Bernstein <max.bernstein@shopify.com>2025-03-25 12:26:04 -0400
committerTakashi Kokubun <takashikkbn@gmail.com>2025-04-18 21:53:01 +0900
commit556fda08640d69bf18f704f8983cf9bfe2bd9f7c (patch)
tree76481c8951a2c265bf5df410a0790e388acedccc
parentd9720eaf10ed1dda3c2a9b9b4f4b8254b33a0c3c (diff)
Use expect-test for HIR tests
This makes it easier to update cascading test failures while still making output reviewable in the PR.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/13131
-rw-r--r--doc/zjit.md10
-rw-r--r--zjit/Cargo.lock25
-rw-r--r--zjit/Cargo.toml3
-rw-r--r--zjit/src/cruby.rs28
-rw-r--r--zjit/src/hir.rs167
5 files changed, 121 insertions, 112 deletions
diff --git a/doc/zjit.md b/doc/zjit.md
index a6e2f745d9..e71a0df539 100644
--- a/doc/zjit.md
+++ b/doc/zjit.md
@@ -50,6 +50,16 @@ You can also run a single test case by specifying the function name:
make zjit-test ZJIT_TESTS=test_putobject
```
+If you expect that your changes cause tests to fail and they do, you can have
+`expect-test` fix the expected value for you by putting `UPDATE_EXPECT=1`
+before your test command, like so:
+
+```
+UPDATE_EXPECT=1 make zjit-test ZJIT_TESTS=test_putobject
+```
+
+Test changes will be reviewed alongside code changes.
+
<details>
<summary>Setting up zjit-test</summary>
diff --git a/zjit/Cargo.lock b/zjit/Cargo.lock
index fa15927f01..57bfb31cd7 100644
--- a/zjit/Cargo.lock
+++ b/zjit/Cargo.lock
@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
-version = 3
+version = 4
[[package]]
name = "capstone"
@@ -32,12 +32,34 @@ dependencies = [
]
[[package]]
+name = "dissimilar"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8975ffdaa0ef3661bfe02dbdcc06c9f829dfafe6a3c474de366a8d5e44276921"
+
+[[package]]
+name = "expect-test"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63af43ff4431e848fb47472a920f14fa71c24de13255a5692e93d4e90302acb0"
+dependencies = [
+ "dissimilar",
+ "once_cell",
+]
+
+[[package]]
name = "libc"
version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
+name = "once_cell"
+version = "1.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
+
+[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -48,4 +70,5 @@ name = "zjit"
version = "0.0.1"
dependencies = [
"capstone",
+ "expect-test",
]
diff --git a/zjit/Cargo.toml b/zjit/Cargo.toml
index 710f67dfd7..ed8e66be02 100644
--- a/zjit/Cargo.toml
+++ b/zjit/Cargo.toml
@@ -25,6 +25,9 @@ lto = "thin"
# written rationale. Optional For development and testing purposes
capstone = { version = "0.13.0", optional = true }
+[dev-dependencies]
+expect-test = "1.5.1"
+
# NOTE: Development builds select a set of these via configure.ac
# For debugging, `make V=1` shows exact cargo invocation.
[features]
diff --git a/zjit/src/cruby.rs b/zjit/src/cruby.rs
index 601a28002b..a187578542 100644
--- a/zjit/src/cruby.rs
+++ b/zjit/src/cruby.rs
@@ -1001,34 +1001,6 @@ pub mod test_utils {
unsafe { rb_iseqw_to_iseq(wrapped_iseq) }
}
- /// Return a diff-like format describing the differences between the two strings. Not very
- /// advanced (does not try to do any anchoring); best for subtle line-local differences.
- pub fn diff_text(expected: &str, actual: &str) -> String {
- let expected_lines: Vec<&str> = expected.lines().collect();
- let actual_lines: Vec<&str> = actual.lines().collect();
- let mut result: String = "Differences found (-expected, +actual):\n---\n".into();
- let max_lines = expected_lines.len().max(actual_lines.len());
- for i in 0..max_lines {
- match (expected_lines.get(i), actual_lines.get(i)) {
- (Some(exp), Some(act)) if exp == act => {
- result.push_str(format!(" {exp}\n").as_ref());
- }
- (Some(exp), Some(act)) => {
- result.push_str(format!("-{exp}\n+{act}\n").as_ref());
- }
- (Some(exp), None) => {
- result.push_str(format!("-{exp}\n").as_ref());
- }
- (None, Some(act)) => {
- result.push_str(format!("+{act}\n").as_ref());
- }
- (None, None) => unreachable!(),
- }
- }
- result.push_str("---\n");
- result
- }
-
/// Remove the minimum indent from every line, skipping the first and last lines if `trim_lines`.
pub fn unindent(string: &str, trim_lines: bool) -> String {
// Break up a string into multiple lines
diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs
index fb7943e576..6e75cec09e 100644
--- a/zjit/src/hir.rs
+++ b/zjit/src/hir.rs
@@ -1662,6 +1662,7 @@ mod infer_tests {
#[cfg(test)]
mod tests {
use super::*;
+ use expect_test::{expect, Expect};
#[macro_export]
macro_rules! assert_matches {
@@ -1698,48 +1699,47 @@ mod tests {
}
#[track_caller]
- fn assert_method_hir(method: &str, hir: &str) {
+ fn assert_method_hir(method: &str, hir: Expect) {
let iseq = crate::cruby::with_rubyvm(|| get_method_iseq(method));
let function = iseq_to_hir(iseq).unwrap();
assert_function_hir(function, hir);
}
#[track_caller]
- pub fn assert_function_hir(function: Function, hir: &str) {
+ pub fn assert_function_hir(function: Function, expected_hir: Expect) {
let actual_hir = format!("{}", FunctionPrinter::without_snapshot(&function));
- let expected_hir = unindent(hir, true);
- assert_eq!(actual_hir, expected_hir, "{}", diff_text(&expected_hir, &actual_hir));
+ expected_hir.assert_eq(&actual_hir);
}
#[test]
fn test_putobject() {
eval("def test = 123");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0():
v1:Fixnum[123] = Const Value(123)
Return v1
- ");
+ "#]]);
}
#[test]
fn test_new_array() {
eval("def test = []");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0():
v1:ArrayExact = NewArray 0
Return v1
- ");
+ "#]]);
}
#[test]
fn test_array_dup() {
eval("def test = [1, 2, 3]");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0():
v1:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
v2:ArrayExact = ArrayDup v1
Return v2
- ");
+ "#]]);
}
// TODO(max): Test newhash when we have it
@@ -1747,64 +1747,64 @@ mod tests {
#[test]
fn test_string_copy() {
eval("def test = \"hello\"");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0():
v1:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
v2:StringExact = StringCopy { val: InsnId(1) }
Return v2
- ");
+ "#]]);
}
#[test]
fn test_bignum() {
eval("def test = 999999999999999999999999999999999999");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0():
v1:Bignum[VALUE(0x1000)] = Const Value(VALUE(0x1000))
Return v1
- ");
+ "#]]);
}
#[test]
fn test_flonum() {
eval("def test = 1.5");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0():
v1:Flonum[VALUE(0x1000)] = Const Value(VALUE(0x1000))
Return v1
- ");
+ "#]]);
}
#[test]
fn test_heap_float() {
eval("def test = 1.7976931348623157e+308");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0():
v1:HeapFloat[VALUE(0x1000)] = Const Value(VALUE(0x1000))
Return v1
- ");
+ "#]]);
}
#[test]
fn test_static_sym() {
eval("def test = :foo");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0():
v1:StaticSymbol[VALUE(0x1000)] = Const Value(VALUE(0x1000))
Return v1
- ");
+ "#]]);
}
#[test]
fn test_opt_plus() {
eval("def test = 1+2");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0():
v1:Fixnum[1] = Const Value(1)
v3:Fixnum[2] = Const Value(2)
v5:BasicObject = SendWithoutBlock v1, :+, v3
Return v5
- ");
+ "#]]);
}
#[test]
@@ -1815,12 +1815,12 @@ mod tests {
a
end
");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0():
v0:NilClassExact = Const Value(nil)
v2:Fixnum[1] = Const Value(1)
Return v2
- ");
+ "#]]);
}
#[test]
@@ -1834,7 +1834,7 @@ mod tests {
end
end
");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0(v0:BasicObject):
v3:CBool = Test v0
IfFalse v3, bb1(v0)
@@ -1843,7 +1843,7 @@ mod tests {
bb1(v9:BasicObject):
v11:Fixnum[4] = Const Value(4)
Return v11
- ");
+ "#]]);
}
#[test]
@@ -1858,7 +1858,7 @@ mod tests {
result
end
");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0(v0:BasicObject):
v1:NilClassExact = Const Value(nil)
v4:CBool = Test v0
@@ -1870,7 +1870,7 @@ mod tests {
Jump bb2(v11, v14)
bb2(v17:BasicObject, v18:Fixnum):
Return v18
- ");
+ "#]]);
}
#[test]
@@ -1879,14 +1879,14 @@ mod tests {
def test(a, b) = a + b
test(1, 2); test(1, 2)
");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0(v0:BasicObject, v1:BasicObject):
PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_PLUS)
v6:Fixnum = GuardType v0, Fixnum
v7:Fixnum = GuardType v1, Fixnum
v8:Fixnum = FixnumAdd v6, v7
Return v8
- ");
+ "#]]);
}
#[test]
@@ -1895,14 +1895,14 @@ mod tests {
def test(a, b) = a - b
test(1, 2); test(1, 2)
");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0(v0:BasicObject, v1:BasicObject):
PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_MINUS)
v6:Fixnum = GuardType v0, Fixnum
v7:Fixnum = GuardType v1, Fixnum
v8:Fixnum = FixnumSub v6, v7
Return v8
- ");
+ "#]]);
}
#[test]
@@ -1911,14 +1911,14 @@ mod tests {
def test(a, b) = a * b
test(1, 2); test(1, 2)
");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0(v0:BasicObject, v1:BasicObject):
PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_MULT)
v6:Fixnum = GuardType v0, Fixnum
v7:Fixnum = GuardType v1, Fixnum
v8:Fixnum = FixnumMult v6, v7
Return v8
- ");
+ "#]]);
}
#[test]
@@ -1927,14 +1927,14 @@ mod tests {
def test(a, b) = a / b
test(1, 2); test(1, 2)
");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0(v0:BasicObject, v1:BasicObject):
PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_DIV)
v6:Fixnum = GuardType v0, Fixnum
v7:Fixnum = GuardType v1, Fixnum
v8:Fixnum = FixnumDiv v6, v7
Return v8
- ");
+ "#]]);
}
#[test]
@@ -1943,14 +1943,14 @@ mod tests {
def test(a, b) = a % b
test(1, 2); test(1, 2)
");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0(v0:BasicObject, v1:BasicObject):
PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_MOD)
v6:Fixnum = GuardType v0, Fixnum
v7:Fixnum = GuardType v1, Fixnum
v8:Fixnum = FixnumMod v6, v7
Return v8
- ");
+ "#]]);
}
#[test]
@@ -1959,14 +1959,14 @@ mod tests {
def test(a, b) = a == b
test(1, 2); test(1, 2)
");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0(v0:BasicObject, v1:BasicObject):
PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_EQ)
v6:Fixnum = GuardType v0, Fixnum
v7:Fixnum = GuardType v1, Fixnum
v8:BoolExact = FixnumEq v6, v7
Return v8
- ");
+ "#]]);
}
#[test]
@@ -1975,14 +1975,14 @@ mod tests {
def test(a, b) = a != b
test(1, 2); test(1, 2)
");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0(v0:BasicObject, v1:BasicObject):
PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_NEQ)
v6:Fixnum = GuardType v0, Fixnum
v7:Fixnum = GuardType v1, Fixnum
v8:BoolExact = FixnumNeq v6, v7
Return v8
- ");
+ "#]]);
}
#[test]
@@ -1991,14 +1991,14 @@ mod tests {
def test(a, b) = a < b
test(1, 2); test(1, 2)
");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0(v0:BasicObject, v1:BasicObject):
PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_LT)
v6:Fixnum = GuardType v0, Fixnum
v7:Fixnum = GuardType v1, Fixnum
v8:BoolExact = FixnumLt v6, v7
Return v8
- ");
+ "#]]);
}
#[test]
@@ -2007,14 +2007,14 @@ mod tests {
def test(a, b) = a <= b
test(1, 2); test(1, 2)
");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0(v0:BasicObject, v1:BasicObject):
PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_LE)
v6:Fixnum = GuardType v0, Fixnum
v7:Fixnum = GuardType v1, Fixnum
v8:BoolExact = FixnumLe v6, v7
Return v8
- ");
+ "#]]);
}
#[test]
@@ -2023,14 +2023,14 @@ mod tests {
def test(a, b) = a > b
test(1, 2); test(1, 2)
");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0(v0:BasicObject, v1:BasicObject):
PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_GT)
v6:Fixnum = GuardType v0, Fixnum
v7:Fixnum = GuardType v1, Fixnum
v8:BoolExact = FixnumGt v6, v7
Return v8
- ");
+ "#]]);
}
#[test]
@@ -2047,7 +2047,7 @@ mod tests {
end
test
");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0():
v0:NilClassExact = Const Value(nil)
v1:NilClassExact = Const Value(nil)
@@ -2076,7 +2076,7 @@ mod tests {
v46:Fixnum[1] = GuardType v42, Fixnum
v47:Fixnum = FixnumSub v45, v46
Jump bb2(v38, v47)
- ");
+ "#]]);
}
#[test]
@@ -2085,14 +2085,14 @@ mod tests {
def test(a, b) = a >= b
test(1, 2); test(1, 2)
");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0(v0:BasicObject, v1:BasicObject):
PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_GE)
v6:Fixnum = GuardType v0, Fixnum
v7:Fixnum = GuardType v1, Fixnum
v8:BoolExact = FixnumGe v6, v7
Return v8
- ");
+ "#]]);
}
#[test]
@@ -2107,7 +2107,7 @@ mod tests {
end
end
");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0():
v0:NilClassExact = Const Value(nil)
v2:TrueClassExact = Const Value(true)
@@ -2118,7 +2118,7 @@ mod tests {
bb1(v12):
v14 = Const Value(4)
Return v14
- ");
+ "#]]);
}
#[test]
@@ -2132,14 +2132,14 @@ mod tests {
end
test
");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0():
v1:BasicObject = PutSelf
v3:Fixnum[2] = Const Value(2)
v5:Fixnum[3] = Const Value(3)
v7:BasicObject = SendWithoutBlock v1, :bar, v3, v5
Return v7
- ");
+ "#]]);
}
#[test]
@@ -2152,11 +2152,11 @@ mod tests {
end
test([1,2,3])
");
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0(v0:BasicObject):
v3:BasicObject = Send v0, 0x1000, :each
Return v3
- ");
+ "#]]);
}
#[test]
@@ -2164,7 +2164,7 @@ mod tests {
eval("def test = unknown_method([0], [1], '2', '2')");
// The 2 string literals have the same address because they're deduped.
- assert_method_hir("test", "
+ assert_method_hir("test", expect![[r#"
bb0():
v1:BasicObject = PutSelf
v3:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
@@ -2177,7 +2177,7 @@ mod tests {
v13:StringExact = StringCopy { val: InsnId(12) }
v15:BasicObject = SendWithoutBlock v1, :unknown_method, v4, v7, v10, v13
Return v15
- ");
+ "#]]);
}
}
@@ -2185,9 +2185,10 @@ mod tests {
mod opt_tests {
use super::*;
use super::tests::assert_function_hir;
+ use expect_test::{expect, Expect};
#[track_caller]
- fn assert_optimized_method_hir(method: &str, hir: &str) {
+ fn assert_optimized_method_hir(method: &str, hir: Expect) {
let iseq = crate::cruby::with_rubyvm(|| get_method_iseq(method));
let mut function = iseq_to_hir(iseq).unwrap();
function.optimize();
@@ -2206,14 +2207,14 @@ mod opt_tests {
end
end
");
- assert_optimized_method_hir("test", "
+ assert_optimized_method_hir("test", expect![[r#"
bb0():
v0:NilClassExact = Const Value(nil)
v2:TrueClassExact = Const Value(true)
v17:CBool[true] = Const CBool(true)
v9:Fixnum[3] = Const Value(3)
Return v9
- ");
+ "#]]);
}
#[test]
@@ -2228,7 +2229,7 @@ mod opt_tests {
end
end
");
- assert_optimized_method_hir("test", "
+ assert_optimized_method_hir("test", expect![[r#"
bb0():
v0:NilClassExact = Const Value(nil)
v2:FalseClassExact = Const Value(false)
@@ -2237,7 +2238,7 @@ mod opt_tests {
bb1(v12:FalseClassExact):
v14:Fixnum[4] = Const Value(4)
Return v14
- ");
+ "#]]);
}
#[test]
@@ -2248,7 +2249,7 @@ mod opt_tests {
end
test; test
");
- assert_optimized_method_hir("test", "
+ assert_optimized_method_hir("test", expect![[r#"
bb0():
v1:Fixnum[1] = Const Value(1)
v3:Fixnum[2] = Const Value(2)
@@ -2258,7 +2259,7 @@ mod opt_tests {
PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_PLUS)
v19:Fixnum[6] = Const Value(6)
Return v19
- ");
+ "#]]);
}
#[test]
@@ -2273,16 +2274,16 @@ mod opt_tests {
end
test; test
");
- assert_optimized_method_hir("test", "
-bb0():
- v1:Fixnum[1] = Const Value(1)
- v3:Fixnum[2] = Const Value(2)
- PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_LT)
- v20:TrueClassExact = Const Value(true)
- v21:CBool[true] = Const CBool(true)
- v13:Fixnum[3] = Const Value(3)
- Return v13
- ");
+ assert_optimized_method_hir("test", expect![[r#"
+ bb0():
+ v1:Fixnum[1] = Const Value(1)
+ v3:Fixnum[2] = Const Value(2)
+ PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_LT)
+ v20:TrueClassExact = Const Value(true)
+ v21:CBool[true] = Const CBool(true)
+ v13:Fixnum[3] = Const Value(3)
+ Return v13
+ "#]]);
}
#[test]
@@ -2297,7 +2298,7 @@ bb0():
end
test; test
");
- assert_optimized_method_hir("test", "
+ assert_optimized_method_hir("test", expect![[r#"
bb0():
v1:Fixnum[1] = Const Value(1)
v3:Fixnum[2] = Const Value(2)
@@ -2308,7 +2309,7 @@ bb0():
bb1():
v17:Fixnum[4] = Const Value(4)
Return v17
- ");
+ "#]]);
}
#[test]
@@ -2323,7 +2324,7 @@ bb0():
end
test; test
");
- assert_optimized_method_hir("test", "
+ assert_optimized_method_hir("test", expect![[r#"
bb0():
v1:Fixnum[2] = Const Value(2)
v3:Fixnum[2] = Const Value(2)
@@ -2332,7 +2333,7 @@ bb0():
v21:CBool[true] = Const CBool(true)
v13:Fixnum[3] = Const Value(3)
Return v13
- ");
+ "#]]);
}
#[test]
@@ -2343,13 +2344,13 @@ bb0():
end
test(2); test(3)
");
- assert_optimized_method_hir("test", "
+ assert_optimized_method_hir("test", expect![[r#"
bb0(v0:BasicObject):
v3:Fixnum[1] = Const Value(1)
PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_PLUS)
v6:Fixnum = GuardType v0, Fixnum
v8:Fixnum = FixnumAdd v6, v3
Return v8
- ");
+ "#]]);
}
}