319 lines
10 KiB
Dart
319 lines
10 KiB
Dart
import 'package:test/test.dart';
|
|
import 'package:d4rt_formulas/formula_models.dart';
|
|
import 'package:d4rt_formulas/formula_evaluator.dart';
|
|
|
|
void main() {
|
|
group('FormulaEvaluator', () {
|
|
late FormulaEvaluator evaluator;
|
|
|
|
setUp(() {
|
|
evaluator = FormulaEvaluator();
|
|
});
|
|
|
|
group('Basic evaluation', () {
|
|
test('evaluates Newton\'s second law formula', () {
|
|
final formula = Formula(
|
|
name: "Newton's second law",
|
|
input: [
|
|
VariableSpec(name: 'm', unit: 'mass'),
|
|
VariableSpec(name: 'a', unit: 'acceleration'),
|
|
],
|
|
output: VariableSpec(name: 'F', unit: 'force'),
|
|
d4rtCode: '''
|
|
F = a * m;
|
|
''',
|
|
);
|
|
|
|
final result = evaluator.evaluate(formula, {
|
|
'm': 10.0, // 10 kg
|
|
'a': 9.8, // 9.8 m/s²
|
|
});
|
|
|
|
expect(result, 98.0); // F = m * a = 10 * 9.8 = 98 N
|
|
});
|
|
|
|
test('evaluates simple arithmetic formula', () {
|
|
final formula = Formula(
|
|
name: 'Simple addition',
|
|
input: [
|
|
VariableSpec(name: 'x', unit: 'scalar'),
|
|
VariableSpec(name: 'y', unit: 'scalar'),
|
|
],
|
|
output: VariableSpec(name: 'result', unit: 'scalar'),
|
|
d4rtCode: '''
|
|
result = x + y;
|
|
''',
|
|
);
|
|
|
|
final result = evaluator.evaluate(formula, {'x': 5, 'y': 3});
|
|
|
|
expect(result, 8);
|
|
});
|
|
|
|
test('handles single input variable', () {
|
|
final formula = Formula(
|
|
name: 'Square function',
|
|
input: [VariableSpec(name: 'n', unit: 'scalar')],
|
|
output: VariableSpec(name: 'result', unit: 'scalar'),
|
|
d4rtCode: '''
|
|
result = n * n;
|
|
''',
|
|
);
|
|
|
|
final result = evaluator.evaluate(formula, {'n': 7});
|
|
expect(result, 49);
|
|
});
|
|
|
|
test('handles complex mathematical operations', () {
|
|
final formula = Formula(
|
|
name: 'Quadratic formula discriminant',
|
|
input: [
|
|
VariableSpec(name: 'a', unit: 'scalar'),
|
|
VariableSpec(name: 'b', unit: 'scalar'),
|
|
VariableSpec(name: 'c', unit: 'scalar'),
|
|
],
|
|
output: VariableSpec(name: 'discriminant', unit: 'scalar'),
|
|
d4rtCode: '''
|
|
discriminant = b * b - 4 * a * c;
|
|
''',
|
|
);
|
|
|
|
final result = evaluator.evaluate(formula, {'a': 1, 'b': 5, 'c': 6});
|
|
|
|
expect(result, 1); // b² - 4ac = 25 - 24 = 1
|
|
});
|
|
});
|
|
|
|
group('Input variable order', () {
|
|
test('maintains consistent alphabetical order for input variables', () {
|
|
final formula = Formula(
|
|
name: 'Test order',
|
|
input: [
|
|
VariableSpec(name: 'z', unit: 'scalar'),
|
|
VariableSpec(name: 'a', unit: 'scalar'),
|
|
VariableSpec(name: 'b', unit: 'scalar'),
|
|
],
|
|
output: VariableSpec(name: 'result', unit: 'scalar'),
|
|
d4rtCode: 'result = a + b + z;',
|
|
);
|
|
|
|
final order = evaluator.getInputVariableOrder(formula);
|
|
expect(order, ['a', 'b', 'z']);
|
|
});
|
|
|
|
test('passes arguments in correct alphabetical order', () {
|
|
final formula = Formula(
|
|
name: 'Test argument order',
|
|
input: [
|
|
VariableSpec(name: 'z', unit: 'scalar'),
|
|
VariableSpec(name: 'a', unit: 'scalar'),
|
|
VariableSpec(name: 'y', unit: 'scalar'),
|
|
],
|
|
output: VariableSpec(name: 'result', unit: 'scalar'),
|
|
d4rtCode: '''
|
|
// Variables: a=1, y=2, z=3
|
|
result = a * 100 + y * 10 + z;
|
|
''',
|
|
);
|
|
|
|
final result = evaluator.evaluate(formula, {'z': 3, 'a': 1, 'y': 2});
|
|
|
|
expect(result, 123); // 1*100 + 2*10 + 3 = 123
|
|
});
|
|
});
|
|
|
|
group('Error handling', () {
|
|
|
|
test('throws exception for missing input variables', () {
|
|
final formula = Formula(
|
|
name: 'Test formula',
|
|
input: [
|
|
VariableSpec(name: 'x', unit: 'scalar'),
|
|
VariableSpec(name: 'y', unit: 'scalar'),
|
|
],
|
|
output: VariableSpec(name: 'result', unit: 'scalar'),
|
|
d4rtCode: 'result = x + y;',
|
|
);
|
|
|
|
expect(
|
|
() => evaluator.evaluate(formula, {'x': 1}), // Missing 'y'
|
|
throwsA(isA<FormulaEvaluationException>()),
|
|
);
|
|
});
|
|
|
|
});
|
|
|
|
group('Utility methods', () {
|
|
test('getOutputVariableName returns the single output variable name', () {
|
|
final formula = Formula(
|
|
name: 'Test',
|
|
input: [VariableSpec(name: 'x', unit: 'scalar')],
|
|
output: VariableSpec(name: 'force', unit: 'Newton'),
|
|
d4rtCode: 'force = x;',
|
|
);
|
|
|
|
expect(formula.output.name, 'force');
|
|
});
|
|
|
|
test(
|
|
'getOutputVariableMagnitude returns the output variable magnitude',
|
|
() {
|
|
final formula = Formula(
|
|
name: 'Test',
|
|
input: [VariableSpec(name: 'x', unit: 'scalar')],
|
|
output: VariableSpec(name: 'force', unit: 'Newton'),
|
|
d4rtCode: 'force = x;',
|
|
);
|
|
|
|
expect(formula.output.unit, 'Newton');
|
|
},
|
|
);
|
|
|
|
test('utility methods work correctly with valid formulas', () {
|
|
final validFormula = Formula(
|
|
name: 'Valid Formula',
|
|
input: [VariableSpec(name: 'x', unit: 'scalar')],
|
|
output: VariableSpec(name: 'result', unit: 'Newton'),
|
|
d4rtCode: 'result = x;',
|
|
);
|
|
|
|
expect(validFormula.output.name, 'result');
|
|
expect(validFormula.output.unit, 'Newton');
|
|
});
|
|
|
|
});
|
|
|
|
group('Data types', () {
|
|
test('handles integer values', () {
|
|
final formula = Formula(
|
|
name: 'Integer test',
|
|
input: [VariableSpec(name: 'n', unit: 'count')],
|
|
output: VariableSpec(name: 'result', unit: 'count'),
|
|
d4rtCode: 'result = n + 1;',
|
|
);
|
|
|
|
final result = evaluator.evaluate(formula, {'n': 42});
|
|
expect(result, 43);
|
|
});
|
|
|
|
test('handles double values', () {
|
|
final formula = Formula(
|
|
name: 'Double test',
|
|
input: [VariableSpec(name: 'x', unit: 'length')],
|
|
output: VariableSpec(name: 'result', unit: 'area'),
|
|
d4rtCode: 'result = x * x;',
|
|
);
|
|
|
|
final result = evaluator.evaluate(formula, {'x': 3.14});
|
|
expect(result, closeTo(9.8596, 0.0001));
|
|
});
|
|
});
|
|
|
|
group('APGAR Score', () {
|
|
test('evaluates APGAR score formula - Normal case', () {
|
|
final formula = Formula(
|
|
name: "Apgar Score",
|
|
description: "Newborn health assessment scoring system",
|
|
input: [
|
|
VariableSpec(name: "HeartRate", values: ["hr1", "hr2", "hr3"]),
|
|
VariableSpec(name: "Breathing", values: ["hr1", "hr2", "hr3"]),
|
|
VariableSpec(name: "MuscleTone", values: ["hr1", "hr2", "hr3"]),
|
|
VariableSpec(name: "Reflexes", values: ["hr1", "hr2", "hr3"]),
|
|
VariableSpec(name: "SkinColor", values: ["hr1", "hr2", "hr3"])
|
|
],
|
|
output: VariableSpec(name: "Result", unit: "stringscalar"),
|
|
d4rtCode: """
|
|
var total = HeartRate + Breathing + MuscleTone + Reflexes + SkinColor;
|
|
var interpretation = switch (total) {
|
|
>= 7 => 'Normal',
|
|
4-6 => 'Requires attention',
|
|
_ => 'Emergency care needed'
|
|
};
|
|
Result = 'Score: \$total - \$interpretation';
|
|
""",
|
|
);
|
|
|
|
// Test normal case (score 7-10)
|
|
final result = evaluator.evaluate(formula, {
|
|
'HeartRate': 2,
|
|
'Breathing': 2,
|
|
'MuscleTone': 2,
|
|
'Reflexes': 2,
|
|
'SkinColor': 2
|
|
});
|
|
|
|
expect(result, 'Score: 10 - Normal');
|
|
});
|
|
|
|
test('evaluates APGAR score formula - Requires attention case', () {
|
|
final formula = Formula(
|
|
name: "Apgar Score",
|
|
description: "Newborn health assessment scoring system",
|
|
input: [
|
|
VariableSpec(name: "HeartRate", values: ["hr1", "hr2", "hr3"]),
|
|
VariableSpec(name: "Breathing", values: ["hr1", "hr2", "hr3"]),
|
|
VariableSpec(name: "MuscleTone", values: ["hr1", "hr2", "hr3"]),
|
|
VariableSpec(name: "Reflexes", values: ["hr1", "hr2", "hr3"]),
|
|
VariableSpec(name: "SkinColor", values: ["hr1", "hr2", "hr3"])
|
|
],
|
|
output: VariableSpec(name: "Result", unit: "stringscalar"),
|
|
d4rtCode: """
|
|
var total = HeartRate + Breathing + MuscleTone + Reflexes + SkinColor;
|
|
var interpretation = switch (total) {
|
|
>= 7 => 'Normal',
|
|
4-6 => 'Requires attention',
|
|
_ => 'Emergency care needed'
|
|
};
|
|
Result = 'Score: \$total - \$interpretation';
|
|
""",
|
|
);
|
|
|
|
// Test requires attention case (score 4-6)
|
|
final result = evaluator.evaluate(formula, {
|
|
'HeartRate': 1,
|
|
'Breathing': 1,
|
|
'MuscleTone': 1,
|
|
'Reflexes': 1,
|
|
'SkinColor': 2
|
|
});
|
|
|
|
expect(result, 'Score: 6 - Requires attention');
|
|
});
|
|
|
|
test('evaluates APGAR score formula - Emergency case', () {
|
|
final formula = Formula(
|
|
name: "Apgar Score",
|
|
description: "Newborn health assessment scoring system",
|
|
input: [
|
|
VariableSpec(name: "HeartRate", values: ["hr1", "hr2", "hr3"]),
|
|
VariableSpec(name: "Breathing", values: ["hr1", "hr2", "hr3"]),
|
|
VariableSpec(name: "MuscleTone", values: ["hr1", "hr2", "hr3"]),
|
|
VariableSpec(name: "Reflexes", values: ["hr1", "hr2", "hr3"]),
|
|
VariableSpec(name: "SkinColor", values: ["hr1", "hr2", "hr3"])
|
|
],
|
|
output: VariableSpec(name: "Result", unit: "stringscalar"),
|
|
d4rtCode: """
|
|
var total = HeartRate + Breathing + MuscleTone + Reflexes + SkinColor;
|
|
var interpretation = switch (total) {
|
|
>= 7 => 'Normal',
|
|
4-6 => 'Requires attention',
|
|
_ => 'Emergency care needed'
|
|
};
|
|
Result = 'Score: \$total - \$interpretation';
|
|
""",
|
|
);
|
|
|
|
// Test emergency case (score 0-3)
|
|
final result = evaluator.evaluate(formula, {
|
|
'HeartRate': 0,
|
|
'Breathing': 0,
|
|
'MuscleTone': 1,
|
|
'Reflexes': 0,
|
|
'SkinColor': 1
|
|
});
|
|
|
|
expect(result, 'Score: 2 - Emergency care needed');
|
|
});
|
|
});
|
|
});
|
|
}
|