Skip to content

Commit 099c84d

Browse files
committed
Unit test substitution (#100)
1 parent a622b16 commit 099c84d

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed

unit/src/ParsedTensorTest.C

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
/**********************************************************************/
88

99
#include "ParsedJITTensor.h"
10+
#include "SwiftExpressionParser.h"
1011
#include "SwiftUtils.h"
1112
#include "MooseError.h"
1213
#include "gtest/gtest.h"
@@ -201,3 +202,109 @@ TEST(ParsedTensorTest, Parse)
201202
check2("a:=sin(x^2); a + 2*a + 3*a", "x", "12*x*cos(x^2)", true);
202203
check2("a:=sin(x^2); a + 2*a + 3*a", "x", "12*x*cos(x^2)", false);
203204
}
205+
206+
TEST(ParsedTensorTest, Substitute)
207+
{
208+
SwiftExpressionParser::Parser parser;
209+
210+
// Test basic variable substitution
211+
{
212+
auto expr = parser.parse("x + y");
213+
ASSERT_TRUE(expr != nullptr);
214+
215+
auto replacement = parser.parse("2*z");
216+
ASSERT_TRUE(replacement != nullptr);
217+
218+
auto substituted = expr->substitute("x", replacement);
219+
EXPECT_EQ(substituted->toString(), "((2.000000 * z) + y)");
220+
}
221+
{
222+
auto expr = parser.parse("x * y");
223+
ASSERT_TRUE(expr != nullptr);
224+
225+
auto replacement = parser.parse("2+z");
226+
ASSERT_TRUE(replacement != nullptr);
227+
228+
auto substituted = expr->substitute("x", replacement);
229+
EXPECT_EQ(substituted->toString(), "((2.000000 + z) * y)");
230+
}
231+
232+
// Test substitution in nested expressions
233+
{
234+
auto expr = parser.parse("sin(x) + cos(x) * x");
235+
ASSERT_TRUE(expr != nullptr);
236+
237+
auto replacement = parser.parse("y^2");
238+
ASSERT_TRUE(replacement != nullptr);
239+
240+
auto substituted = expr->substitute("x", replacement);
241+
EXPECT_EQ(substituted->toString(),
242+
"(sin((y ^ 2.000000)) + (cos((y ^ 2.000000)) * (y ^ 2.000000)))");
243+
}
244+
245+
// Test substitution in let expressions without shadowing
246+
{
247+
auto expr = parser.parse("a := x + 1; a * x");
248+
ASSERT_TRUE(expr != nullptr);
249+
250+
auto replacement = parser.parse("y + z");
251+
ASSERT_TRUE(replacement != nullptr);
252+
253+
auto substituted = expr->substitute("x", replacement);
254+
// Should substitute x in both the binding and the body
255+
EXPECT_EQ(substituted->toString(), "a:=((y + z) + 1.000000); (a * (y + z))");
256+
}
257+
258+
// Test substitution with variable shadowing
259+
{
260+
auto expr = parser.parse("a := x + 1; a * x");
261+
ASSERT_TRUE(expr != nullptr);
262+
263+
auto replacement = parser.parse("y + z");
264+
ASSERT_TRUE(replacement != nullptr);
265+
266+
auto substituted = expr->substitute("a", replacement);
267+
// Should NOT substitute 'a' anywhere because the binding defines 'a' (shadowing)
268+
EXPECT_EQ(substituted->toString(), "a:=(x + 1.000000); (a * x)");
269+
}
270+
271+
// Test that substitution doesn't affect unrelated variables
272+
{
273+
auto expr = parser.parse("x + y + z");
274+
ASSERT_TRUE(expr != nullptr);
275+
276+
auto replacement = parser.parse("42");
277+
ASSERT_TRUE(replacement != nullptr);
278+
279+
auto substituted = expr->substitute("y", replacement);
280+
EXPECT_EQ(substituted->toString(), "((x + 42.000000) + z)");
281+
}
282+
283+
// Test substitution in complex let expressions with multiple bindings
284+
{
285+
auto expr = parser.parse("a := x; b := a + 1; b * x");
286+
ASSERT_TRUE(expr != nullptr);
287+
288+
auto replacement = parser.parse("2*z");
289+
ASSERT_TRUE(replacement != nullptr);
290+
291+
auto substituted = expr->substitute("x", replacement);
292+
// x should be substituted in first binding and in body, but not in second binding (uses 'a')
293+
EXPECT_EQ(substituted->toString(),
294+
"a:=(2.000000 * z); b:=(a + 1.000000); (b * (2.000000 * z))");
295+
}
296+
297+
// Test substitution preserves expression structure
298+
{
299+
auto expr = parser.parse("r := x^2 + y^2; sqrt(r) + r");
300+
ASSERT_TRUE(expr != nullptr);
301+
302+
auto replacement = parser.parse("t + 1");
303+
ASSERT_TRUE(replacement != nullptr);
304+
305+
auto substituted = expr->substitute("x", replacement);
306+
// x should be substituted but local variable r should still be referenced
307+
EXPECT_EQ(substituted->toString(),
308+
"r:=(((t + 1.000000) ^ 2.000000) + (y ^ 2.000000)); (sqrt(r) + r)");
309+
}
310+
}

0 commit comments

Comments
 (0)