Test for d4rt

This commit is contained in:
Álvaro González 2025-09-22 17:00:34 +02:00
parent 80d6c7d0df
commit ba6c761cee
5 changed files with 150 additions and 60 deletions

View file

@ -5,11 +5,11 @@
"description": ''' "description": '''
Calculates vertical displacement under constant gravity Calculates vertical displacement under constant gravity
`h = ½gt²` $$h = \\frac{1}{2}gt^2$$
Where: Where:
- `g` = Gravitational acceleration (9.81 m/s² on Earth) - $g$: Gravitational acceleration ($9.81\\ \\mathrm{m/s^2}$ on Earth)
- `t` = Time in free fall (seconds) - $t$: Time in free fall (seconds)
![Free Fall Diagram](https://altcalculator.com/wp-content/uploads/2023/08/Free-Fall.png)''', ![Free Fall Diagram](https://altcalculator.com/wp-content/uploads/2023/08/Free-Fall.png)''',
"input": [ "input": [
@ -17,7 +17,7 @@ Where:
{"name": "g", "unit": "meters per second"} // Gravitational acceleration {"name": "g", "unit": "meters per second"} // Gravitational acceleration
], ],
"output": {"name": "h", "unit": "meter"}, // Height in meters "output": {"name": "h", "unit": "meter"}, // Height in meters
"d4rtCode": "h = 0.5 * g * Math.pow(t, 2);", "d4rtCode": "h = 0.5 * g * pow(t, 2);",
"tags": ["physics", "kinematics"] "tags": ["physics", "kinematics"]
}, },
@ -27,12 +27,12 @@ Where:
"description": ''' "description": '''
Newton's law of universal gravitation Newton's law of universal gravitation
`F = G(m₁m₂)/r²` $$F = G\\frac{m_1m_2}{r^2}$$
Where: Where:
- `G` = Gravitational constant (6.674×10⁻¹¹ N·m²/kg²) - $G$: Gravitational constant ($6.674\\times 10^{-11}\\ \\mathrm{N\\cdot m^2/kg^2}$)
- `m₁`, `m₂` = Masses of two objects - $m_1, m_2$: Masses of two objects
- `r` = Distance between centers of masses - $r$: Distance between centers of masses
![Gravitation](https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/NewtonsLawOfUniversalGravitation.svg/1200px-NewtonsLawOfUniversalGravitation.svg.png)''', ![Gravitation](https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/NewtonsLawOfUniversalGravitation.svg/1200px-NewtonsLawOfUniversalGravitation.svg.png)''',
"input": [ "input": [
@ -41,7 +41,7 @@ Where:
{"name": "r", "unit": "meter"} // Distance between masses {"name": "r", "unit": "meter"} // Distance between masses
], ],
"output": {"name": "F", "unit": "newton"}, // Force in newtons "output": {"name": "F", "unit": "newton"}, // Force in newtons
"d4rtCode": "F = (6.67430e-11 * m1 * m2) / Math.pow(r, 2);", "d4rtCode": "F = (6.67430e-11 * m1 * m2) / pow(r, 2);",
"tags": ["physics", "astronomy", "gravity"] "tags": ["physics", "astronomy", "gravity"]
}, },
@ -51,11 +51,11 @@ Where:
"description": ''' "description": '''
Energy possessed by a moving object Energy possessed by a moving object
`KE = ½mv²` $$KE = \\frac{1}{2}mv^2$$
Where: Where:
- `m` = Mass of object - $m$: Mass of object
- `v` = Velocity of object - $v$: Velocity of object
![Kinetic Energy](https://upload.wikimedia.org/wikipedia/commons/thumb/4/44/Kinetic_energy.svg/1200px-Kinetic_energy.svg.png)''', ![Kinetic Energy](https://upload.wikimedia.org/wikipedia/commons/thumb/4/44/Kinetic_energy.svg/1200px-Kinetic_energy.svg.png)''',
"input": [ "input": [
@ -63,7 +63,7 @@ Where:
{"name": "v", "unit": "meters per second"} // Velocity {"name": "v", "unit": "meters per second"} // Velocity
], ],
"output": {"name": "KE", "unit": "joule"}, // Energy in joules "output": {"name": "KE", "unit": "joule"}, // Energy in joules
"d4rtCode": "KE = 0.5 * m * Math.pow(v, 2);", "d4rtCode": "KE = 0.5 * m * pow(v, 2);",
"tags": ["physics", "energy", "mechanics"] "tags": ["physics", "energy", "mechanics"]
}, },
@ -71,18 +71,21 @@ Where:
{ {
"name": "Projectile Range", "name": "Projectile Range",
"description": "Calculates horizontal distance of projectile motion\n\n" "description": "Calculates horizontal distance of projectile motion\n\n"
"`R = (v² sin(2θ))/g`\n\n" "$$R = \\frac{v^2 \\sin(2\\theta)}{g}$$\n\n"
"Where:\n" "Where:\n"
"- `v` = Initial velocity\n" "- $v$: Initial velocity\n"
"- `θ` = Launch angle\n" "- $\\theta$: Launch angle\n"
"- `g` = Gravitational acceleration\n\n" "- $g$: Gravitational acceleration\n\n"
"![Projectile Motion](https://upload.wikimedia.org/wikipedia/commons/thumb/5/52/Projectile_motion_diagram.png/800px-Projectile_motion_diagram.png)", "![Projectile Motion](https://upload.wikimedia.org/wikipedia/commons/thumb/5/52/Projectile_motion_diagram.png/800px-Projectile_motion_diagram.png)",
"input": [ "input": [
{"name": "v", "unit": "meters per second"}, // Initial velocity {"name": "v", "unit": "meters per second"}, // Initial velocity
{"name": "θ", "unit": "degree"} // Launch angle {"name": "a", "unit": "degree"} // Launch angle
], ],
"output": {"name": "R", "unit": "meter"}, // Horizontal distance "output": {"name": "R", "unit": "meter"}, // Horizontal distance
"d4rtCode": "R = (Math.pow(v, 2) * sin(2 * radians(θ))) / 9.80665;", "d4rtCode": """
var radians = a * (pi / 180);
R = (pow(v, 2) * sin(2 * radians)) / 9.80665;
""",
"tags": ["physics", "kinematics", "projectile"] "tags": ["physics", "kinematics", "projectile"]
}, },
@ -91,11 +94,11 @@ Where:
"description": ''' "description": '''
Force equals mass times acceleration Force equals mass times acceleration
`F = m * a` $$F = m \\cdot a$$
Where: Where:
- `m` = Mass of object (kg) - $m$: Mass of object ($\\mathrm{kg}$)
- `a` = Acceleration (m/s²) - $a$: Acceleration ($\\mathrm{m/s^2}$)
![Newton's Second Law](https://upload.wikimedia.org/wikipedia/commons/thumb/7/73/Newtonslawsofmotion.jpg/800px-Newtonslawsofmotion.jpg)''', ![Newton's Second Law](https://upload.wikimedia.org/wikipedia/commons/thumb/7/73/Newtonslawsofmotion.jpg/800px-Newtonslawsofmotion.jpg)''',
"input": [ "input": [

View file

@ -46,30 +46,22 @@ class FormulaEvaluator {
final Number exp = getNumberValueOf( positionalArgs[1].toString() ); final Number exp = getNumberValueOf( positionalArgs[1].toString() );
return MyMath.pow(base,exp); return MyMath.pow(base,exp);
}, },
'log': (visitor, positionalArgs, namedArgs) {
final Number x = getNumberValueOf( positionalArgs[0].toString() );
return MyMath.log(x);
},
} }
); );
interpreter.registerBridgedClass(myMathDefinition, 'package:myapp/my_math.dart'); interpreter.registerBridgedClass(myMathDefinition, "package:d4rt_formulas.dart");
} }
dynamic evaluate(Formula formula, Map<String, dynamic> inputValues) { dynamic evaluate(Formula formula, Map<String, dynamic> inputValues) {
_validateInputValues(formula, inputValues); _validateInputValues(formula, inputValues);
final completeSource = _buildCompleteSource(formula, inputValues);
try { final result = _interpreter.execute(source: completeSource);
// Build the complete d4rt source code with variable declarations return result;
final completeSource = _buildCompleteSource(formula, inputValues);
// Execute the code using d4rt (no args needed since variables are in source)
final result = _interpreter.execute(source: completeSource);
return result;
} catch (e) {
throw FormulaEvaluationException(
'Failed to execute formula "${formula.name}"',
e,
);
}
} }
void _validateInputValues(Formula formula, Map<String, dynamic> inputValues) { void _validateInputValues(Formula formula, Map<String, dynamic> inputValues) {
@ -104,8 +96,17 @@ class FormulaEvaluator {
String _buildCompleteSource(Formula formula, Map<String, dynamic> inputValues) { String _buildCompleteSource(Formula formula, Map<String, dynamic> inputValues) {
final buffer = StringBuffer(); final buffer = StringBuffer();
buffer.writeln("import 'package:myapp/my_math.dart';"); buffer.writeln("""
buffer.writeln("main(){"); import 'dart:math';
//log(x) => M.log(x);
//pow(a,b) => M.pow(a,b);
main()
{
"""
);
for (final entry in inputValues.entries) { for (final entry in inputValues.entries) {
final varName = entry.key; final varName = entry.key;
@ -113,16 +114,22 @@ class FormulaEvaluator {
if (value is String) { if (value is String) {
final escapedValue = value.replaceAll('"', '\\"'); final escapedValue = value.replaceAll('"', '\\"');
buffer.writeln('var $varName = "$escapedValue";'); buffer.writeln("""
final $varName = "$escapedValue";
""");
} else { } else {
buffer.writeln('var $varName = $value;'); buffer.writeln("""
final $varName = $value;
""");
} }
} }
buffer.writeln("late var ${getOutputVariableName(formula)};"); buffer.writeln("""
late var ${getOutputVariableName(formula)};
buffer.writeln(formula.d4rtCode); ${formula.d4rtCode}
buffer.writeln("return ${getOutputVariableName(formula)};"); return ${getOutputVariableName(formula)};
buffer.writeln("}"); }
"""
);
return buffer.toString(); return buffer.toString();
} }

View file

@ -299,6 +299,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "2.0.0"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
node_preamble: node_preamble:
dependency: transitive dependency: transitive
description: description:
@ -323,6 +331,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.1" version: "1.9.1"
path_drawing:
dependency: transitive
description:
name: path_drawing
sha256: "3bdd251dae9ffaef944450b73f168610db7e968e7b20daf0c3907f8b4aafc8a2"
url: "https://pub.dev"
source: hosted
version: "0.5.1+1"
path_parsing:
dependency: transitive
description:
name: path_parsing
sha256: ee5c47c1058ad66b4a41746ec3996af9593d0858872807bcd64ac118f0700337
url: "https://pub.dev"
source: hosted
version: "0.2.1"
petitparser:
dependency: transitive
description:
name: petitparser
sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
url: "https://pub.dev"
source: hosted
version: "5.4.0"
pool: pool:
dependency: transitive dependency: transitive
description: description:
@ -331,6 +363,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.5.1" version: "1.5.1"
provider:
dependency: transitive
description:
name: provider
sha256: "59471e0a4595e264625d3496af567ac85bdae1148ec985aff1e0555786f53ecf"
url: "https://pub.dev"
source: hosted
version: "5.0.0"
pub_semver: pub_semver:
dependency: transitive dependency: transitive
description: description:
@ -464,6 +504,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.12" version: "0.6.12"
tuple:
dependency: transitive
description:
name: tuple
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
url: "https://pub.dev"
source: hosted
version: "2.0.2"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@ -528,6 +576,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.1" version: "1.2.1"
xml:
dependency: transitive
description:
name: xml
sha256: "80d494c09849dc3f899d227a78c30c5b949b985ededf884cb3f3bcd39f4b447a"
url: "https://pub.dev"
source: hosted
version: "5.4.1"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:

37
test/d4rt_test.dart Normal file
View file

@ -0,0 +1,37 @@
import 'package:test/test.dart';
import 'package:d4rt/d4rt.dart';
import 'dart:math' as Math;
main(){
test('Access to Math', () {
final completeSource = """
import 'dart:math';
main() => sin(42);
""";
final interpreter = D4rt();
final result = interpreter.execute(source: completeSource);
expect(result, Math.sin(42));
});
test('Access to IO', () {
final completeSource = """
import 'dart:io';
main() {
File file = File('/etc/passwd');
String contents = file.readAsStringSync();
return contents;
}
""";
final interpreter = D4rt();
final result = interpreter.execute(source: completeSource);
expect(result, contains("root"));
});
}

View file

@ -141,19 +141,6 @@ void main() {
); );
}); });
test('throws exception for invalid d4rt code', () {
final formula = Formula(
name: 'Invalid code formula',
input: [VariableSpec(name: 'x', unit: 'scalar')],
output: VariableSpec(name: 'result', unit: 'scalar'),
d4rtCode: 'invalid dart code here!',
);
expect(
() => evaluator.evaluate(formula, {'x': 1}),
throwsA(isA<FormulaEvaluationException>()),
);
});
}); });
group('Utility methods', () { group('Utility methods', () {