can't make valiation on each user interaction
This commit is contained in:
parent
49962b95d6
commit
76769973f3
23 changed files with 198 additions and 82 deletions
3
assets/units/scalar.d4rt.units
Normal file
3
assets/units/scalar.d4rt.units
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
[
|
||||||
|
{"name": "scalar", "symbol": "", "isBase": true},
|
||||||
|
]
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
import '../formula_models.dart';
|
import '../formula_models.dart';
|
||||||
import '../formula_evaluator.dart';
|
import '../formula_evaluator.dart';
|
||||||
|
|
@ -11,11 +9,7 @@ class FormulaScreen extends StatefulWidget {
|
||||||
final Formula formula;
|
final Formula formula;
|
||||||
final Corpus corpus;
|
final Corpus corpus;
|
||||||
|
|
||||||
const FormulaScreen({
|
const FormulaScreen({super.key, required this.formula, required this.corpus});
|
||||||
super.key,
|
|
||||||
required this.formula,
|
|
||||||
required this.corpus,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<FormulaScreen> createState() => _FormulaScreenState();
|
State<FormulaScreen> createState() => _FormulaScreenState();
|
||||||
|
|
@ -24,7 +18,7 @@ class FormulaScreen extends StatefulWidget {
|
||||||
//// Start of D4rtEditingController class ////
|
//// Start of D4rtEditingController class ////
|
||||||
class D4rtEditingController extends TextEditingController {
|
class D4rtEditingController extends TextEditingController {
|
||||||
String? _lastError;
|
String? _lastError;
|
||||||
|
String _text = "";
|
||||||
String? get lastError => _lastError;
|
String? get lastError => _lastError;
|
||||||
FormulaResult? _lastValue;
|
FormulaResult? _lastValue;
|
||||||
|
|
||||||
|
|
@ -46,7 +40,6 @@ class D4rtEditingController extends TextEditingController {
|
||||||
|
|
||||||
get d4rtValue => _lastValue;
|
get d4rtValue => _lastValue;
|
||||||
|
|
||||||
@override
|
|
||||||
set text(String newText) {
|
set text(String newText) {
|
||||||
super.text = newText;
|
super.text = newText;
|
||||||
validate();
|
validate();
|
||||||
|
|
@ -97,27 +90,37 @@ class _FormulaScreenState extends State<FormulaScreen> {
|
||||||
final inputValues = <String, dynamic>{};
|
final inputValues = <String, dynamic>{};
|
||||||
for (final input in widget.formula.input) {
|
for (final input in widget.formula.input) {
|
||||||
final controller = _inputControllers[input.name]!;
|
final controller = _inputControllers[input.name]!;
|
||||||
if( controller.d4rtValue == null ){
|
if (controller.d4rtValue == null) {
|
||||||
throw FormulaEvaluationException( "Field ${input.name} is invalid" );
|
//throw FormulaEvaluationException("Field ${input.name} is invalid");
|
||||||
|
_result = "";
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
final value = controller.d4rtValue.value;
|
|
||||||
|
|
||||||
// Convert input to base unit if needed
|
late final dynamic convertedValue;
|
||||||
// Always convert from dropdown unit to variable's base unit
|
|
||||||
late final convertedValue;
|
switch (controller.d4rtValue) {
|
||||||
if( value is Number && input.unit != null ) {
|
case NumberResult nr:
|
||||||
convertedValue = widget.corpus.convert(
|
// Convert input to base unit if needed
|
||||||
value,
|
// Always convert from dropdown unit to variable's base unit
|
||||||
_selectedUnits[input.name]!,
|
if (input.unit != null) {
|
||||||
input.unit as String,
|
convertedValue = widget.corpus.convert(
|
||||||
);
|
nr.value,
|
||||||
}
|
_selectedUnits[input.name]!,
|
||||||
else{
|
input.unit as String,
|
||||||
convertedValue = value;
|
);
|
||||||
|
} else {
|
||||||
|
convertedValue = nr.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
case StringResult sr:
|
||||||
|
convertedValue = sr.value;
|
||||||
|
default:
|
||||||
|
throw FormulaEvaluationException(
|
||||||
|
"Field ${input.name} has unsupported type ${controller.d4rtValue!.runtimeType}",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
inputValues[input.name] = convertedValue;
|
inputValues[input.name] = convertedValue;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final evaluator = FormulaEvaluator();
|
final evaluator = FormulaEvaluator();
|
||||||
|
|
@ -125,14 +128,11 @@ class _FormulaScreenState extends State<FormulaScreen> {
|
||||||
|
|
||||||
// Convert output to selected unit if needed
|
// Convert output to selected unit if needed
|
||||||
String? unit = widget.formula.output.unit;
|
String? unit = widget.formula.output.unit;
|
||||||
if( unit != null ) {
|
if (unit != null) {
|
||||||
_result = widget.corpus.convert(
|
_result = widget.corpus
|
||||||
result,
|
.convert(result, unit, _selectedOutputUnit!)
|
||||||
unit,
|
.toStringAsFixed(2);
|
||||||
_selectedOutputUnit!,
|
} else {
|
||||||
).toStringAsFixed(2);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
_result = result;
|
_result = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -142,7 +142,7 @@ class _FormulaScreenState extends State<FormulaScreen> {
|
||||||
} catch (e, stack) {
|
} catch (e, stack) {
|
||||||
debugPrint('Formula evaluation error: $e');
|
debugPrint('Formula evaluation error: $e');
|
||||||
debugPrint('Stack trace: $stack');
|
debugPrint('Stack trace: $stack');
|
||||||
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text('Error: ${e.toString()}\n${stack.toString()}'),
|
content: Text('Error: ${e.toString()}\n${stack.toString()}'),
|
||||||
|
|
@ -155,9 +155,7 @@ class _FormulaScreenState extends State<FormulaScreen> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(title: Text(widget.formula.name)),
|
||||||
title: Text(widget.formula.name),
|
|
||||||
),
|
|
||||||
body: Form(
|
body: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
|
@ -176,7 +174,7 @@ class _FormulaScreenState extends State<FormulaScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildDescriptionSection() {
|
Widget _buildDescriptionSection() {
|
||||||
if (widget.formula.description == null ||
|
if (widget.formula.description == null ||
|
||||||
widget.formula.description!.isEmpty) {
|
widget.formula.description!.isEmpty) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
|
|
@ -186,9 +184,9 @@ class _FormulaScreenState extends State<FormulaScreen> {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Description',
|
'Description',
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
style: Theme.of(
|
||||||
fontWeight: FontWeight.bold,
|
context,
|
||||||
),
|
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Container(
|
Container(
|
||||||
|
|
@ -213,9 +211,9 @@ class _FormulaScreenState extends State<FormulaScreen> {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Input Variables',
|
'Input Variables',
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
style: Theme.of(
|
||||||
fontWeight: FontWeight.bold,
|
context,
|
||||||
),
|
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
...widget.formula.input.map((variable) => _buildVariableRow(variable)),
|
...widget.formula.input.map((variable) => _buildVariableRow(variable)),
|
||||||
|
|
@ -229,9 +227,9 @@ class _FormulaScreenState extends State<FormulaScreen> {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Result',
|
'Result',
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
style: Theme.of(
|
||||||
fontWeight: FontWeight.bold,
|
context,
|
||||||
),
|
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Row(
|
Row(
|
||||||
|
|
@ -286,6 +284,7 @@ class _FormulaScreenState extends State<FormulaScreen> {
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
border: UnderlineInputBorder(),
|
border: UnderlineInputBorder(),
|
||||||
),
|
),
|
||||||
|
autovalidateMode: AutovalidateMode.always,
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
return 'Required';
|
return 'Required';
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ class Corpus{
|
||||||
|
|
||||||
List<String> unitsOfSameMagnitude(String? unit){
|
List<String> unitsOfSameMagnitude(String? unit){
|
||||||
if( unit == null ){
|
if( unit == null ){
|
||||||
return ["unitless"];
|
return ["scalar"];
|
||||||
}
|
}
|
||||||
final base = getUnit(unit).baseUnit;
|
final base = getUnit(unit).baseUnit;
|
||||||
return _baseToUnits[base] as List<String>;
|
return _baseToUnits[base] as List<String>;
|
||||||
|
|
@ -90,7 +90,7 @@ class Corpus{
|
||||||
|
|
||||||
String _converterFromCodeStringAsExpression(Number x, String codeString) {
|
String _converterFromCodeStringAsExpression(Number x, String codeString) {
|
||||||
final buffer = StringBuffer();
|
final buffer = StringBuffer();
|
||||||
buffer.writeln("final x = ${x};");
|
buffer.writeln("final x = $x;");
|
||||||
buffer.writeln("main(){return $codeString;}");
|
buffer.writeln("main(){return $codeString;}");
|
||||||
final code = buffer.toString();
|
final code = buffer.toString();
|
||||||
return code;
|
return code;
|
||||||
|
|
@ -98,7 +98,7 @@ class Corpus{
|
||||||
|
|
||||||
String _converterFromCodeStringAsStatement(Number x, String codeString) {
|
String _converterFromCodeStringAsStatement(Number x, String codeString) {
|
||||||
final buffer = StringBuffer();
|
final buffer = StringBuffer();
|
||||||
buffer.writeln("final x = ${x};");
|
buffer.writeln("final x = $x;");
|
||||||
buffer.writeln("main(){ $codeString; return x; }");
|
buffer.writeln("main(){ $codeString; return x; }");
|
||||||
final code = buffer.toString();
|
final code = buffer.toString();
|
||||||
return code;
|
return code;
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,48 @@
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:convert' show utf8;
|
import 'dart:convert' show utf8;
|
||||||
|
import 'package:flutter/services.dart' show rootBundle;
|
||||||
|
|
||||||
import 'package:resource_portable/resource_portable.dart' show Resource;
|
import 'package:resource_portable/resource_portable.dart' show Resource;
|
||||||
|
|
||||||
import '../corpus.dart';
|
import '../corpus.dart';
|
||||||
import '../formula_models.dart';
|
import '../formula_models.dart';
|
||||||
|
|
||||||
|
|
||||||
Future<Corpus> createDefaultCorpus() async{
|
Future<Corpus> createDefaultCorpus() async{
|
||||||
final corpus = Corpus();
|
final corpus = Corpus();
|
||||||
|
|
||||||
|
Future<String> loadResourceAsString(String path) async {
|
||||||
|
return await rootBundle.loadString(path, cache: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<void> loadUnits() async {
|
Future<void> loadUnits() async {
|
||||||
final unitResources = [
|
final unitResources = [
|
||||||
"lib/defaults/units/angle.d4rt.units",
|
"assets/units/angle.d4rt.units",
|
||||||
"lib/defaults/units/area.d4rt.units",
|
"assets/units/area.d4rt.units",
|
||||||
"lib/defaults/units/distance.d4rt.units",
|
"assets/units/distance.d4rt.units",
|
||||||
"lib/defaults/units/energy.d4rt.units",
|
"assets/units/energy.d4rt.units",
|
||||||
"lib/defaults/units/force.d4rt.units",
|
"assets/units/force.d4rt.units",
|
||||||
"lib/defaults/units/mass.d4rt.units",
|
"assets/units/mass.d4rt.units",
|
||||||
"lib/defaults/units/pressure.d4rt.units",
|
"assets/units/pressure.d4rt.units",
|
||||||
"lib/defaults/units/scalar.d4rt.units",
|
"assets/units/scalar.d4rt.units",
|
||||||
"lib/defaults/units/temperature.d4rt.units",
|
"assets/units/temperature.d4rt.units",
|
||||||
"lib/defaults/units/time.d4rt.units",
|
"assets/units/time.d4rt.units",
|
||||||
"lib/defaults/units/velocity.d4rt.units",
|
"assets/units/velocity.d4rt.units",
|
||||||
];
|
];
|
||||||
|
|
||||||
for (final unitRes in unitResources) {
|
for (final unitRes in unitResources) {
|
||||||
final resource = Resource(unitRes);
|
final literal = await loadResourceAsString(unitRes);
|
||||||
final literal = await resource.readAsString(encoding: utf8);
|
|
||||||
final units = UnitSpec.fromArrayStringLiteral(literal);
|
final units = UnitSpec.fromArrayStringLiteral(literal);
|
||||||
corpus.loadUnits(units);
|
corpus.loadUnits(units);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> loadFormulas() async {
|
Future<void> loadFormulas() async {
|
||||||
final formulaResources = ["lib/defaults/formulas.d4rt"];
|
final formulaResources = ["assets/formulas/formulas.d4rt"];
|
||||||
|
|
||||||
for (final formRes in formulaResources) {
|
for (final formRes in formulaResources) {
|
||||||
final resource = Resource(formRes);
|
final literal = await loadResourceAsString(formRes);
|
||||||
final literal = await resource.readAsString(encoding: utf8);
|
|
||||||
final formulas = Formula.fromArrayStringLiteral(literal);
|
final formulas = Formula.fromArrayStringLiteral(literal);
|
||||||
corpus.loadFormulas(formulas);
|
corpus.loadFormulas(formulas);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
[
|
|
||||||
{"name": "scalar", "symbol": "", "isBase": true}
|
|
||||||
]
|
|
||||||
|
|
@ -76,14 +76,14 @@ class FormulaEvaluator {
|
||||||
final d4rtInterpreter = interpreter ?? createDefaultInterpreter();
|
final d4rtInterpreter = interpreter ?? createDefaultInterpreter();
|
||||||
prepareInterpreter(d4rtInterpreter);
|
prepareInterpreter(d4rtInterpreter);
|
||||||
final d4rtCode = """
|
final d4rtCode = """
|
||||||
${d4rtImports}
|
$d4rtImports
|
||||||
main()
|
main()
|
||||||
{
|
{
|
||||||
late var result;
|
late var result;
|
||||||
result = $code;
|
result = $code;
|
||||||
return result;
|
return result;
|
||||||
}""";
|
}""";
|
||||||
//print("evaluateExpression:\n$d4rtCode");
|
print("evaluateExpression:\n$d4rtCode");
|
||||||
final result = d4rtInterpreter.execute(source: d4rtCode);
|
final result = d4rtInterpreter.execute(source: d4rtCode);
|
||||||
switch ( result ){
|
switch ( result ){
|
||||||
case int value:
|
case int value:
|
||||||
|
|
|
||||||
|
|
@ -102,17 +102,17 @@ class UnitSpec {
|
||||||
class VariableSpec {
|
class VariableSpec {
|
||||||
final String name;
|
final String name;
|
||||||
final String? unit;
|
final String? unit;
|
||||||
final List<dynamic>? allowedValues;
|
final List<dynamic>? values;
|
||||||
|
|
||||||
VariableSpec({required this.name, this.unit, this.allowedValues}){
|
VariableSpec({required this.name, this.unit, this.values}){
|
||||||
final valuesValid = allowedValues != null && allowedValues?.isNotEmpty == true;
|
final valuesValid = values != null && values?.isNotEmpty == true;
|
||||||
if( unit == null && !valuesValid ){
|
if( unit == null && !valuesValid ){
|
||||||
throw new ArgumentError("$name: at least unit or allowedValues should be valid");
|
throw ArgumentError("$name: at least unit or allowedValues should be valid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'var($name: $unit${allowedValues != null ? ' allowed: $allowedValues' : ''})';
|
String toString() => 'var($name: $unit${values != null ? ' allowed: $values' : ''})';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
|
|
@ -121,10 +121,10 @@ class VariableSpec {
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
unit == other.unit &&
|
unit == other.unit &&
|
||||||
name == other.name &&
|
name == other.name &&
|
||||||
const DeepCollectionEquality().equals(allowedValues, other.allowedValues);
|
const DeepCollectionEquality().equals(values, other.values);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(unit, name, allowedValues != null ? const DeepCollectionEquality().hash(allowedValues!) : 0);
|
int get hashCode => Object.hash(unit, name, values != null ? const DeepCollectionEquality().hash(values!) : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Formula {
|
class Formula {
|
||||||
|
|
@ -146,7 +146,7 @@ class Formula {
|
||||||
validate();
|
validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
validate() {
|
void validate() {
|
||||||
if (name.trim().isEmpty) {
|
if (name.trim().isEmpty) {
|
||||||
throw ArgumentError('Formula name cannot be empty');
|
throw ArgumentError('Formula name cannot be empty');
|
||||||
}
|
}
|
||||||
|
|
@ -220,7 +220,7 @@ class Formula {
|
||||||
return VariableSpec(
|
return VariableSpec(
|
||||||
name: name,
|
name: name,
|
||||||
unit: unit,
|
unit: unit,
|
||||||
allowedValues: allowed?.toList(growable: false),
|
values: allowed?.toList(growable: false),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import 'corpus.dart';
|
||||||
import 'defaults/default_corpus.dart';
|
import 'defaults/default_corpus.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
runApp(MaterialApp(
|
runApp(MaterialApp(
|
||||||
home: FutureBuilder<Corpus>(
|
home: FutureBuilder<Corpus>(
|
||||||
future: createDefaultCorpus(),
|
future: createDefaultCorpus(),
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,9 @@ flutter:
|
||||||
# assets:
|
# assets:
|
||||||
# - images/a_dot_burr.jpeg
|
# - images/a_dot_burr.jpeg
|
||||||
# - images/a_dot_ham.jpeg
|
# - images/a_dot_ham.jpeg
|
||||||
|
assets:
|
||||||
|
- assets/units/
|
||||||
|
- assets/formulas/
|
||||||
|
|
||||||
# An image asset can refer to one or more resolution-specific "variants", see
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
# https://flutter.dev/to/resolution-aware-images
|
# https://flutter.dev/to/resolution-aware-images
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import 'package:d4rt/d4rt.dart';
|
||||||
import 'dart:math' as Math;
|
import 'dart:math' as Math;
|
||||||
|
|
||||||
|
|
||||||
main(){
|
void main(){
|
||||||
test('Access to Math', () {
|
test('Access to Math', () {
|
||||||
|
|
||||||
final completeSource = """
|
final completeSource = """
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import 'package:d4rt/d4rt.dart';
|
||||||
import 'dart:math' as Math;
|
import 'dart:math' as Math;
|
||||||
|
|
||||||
|
|
||||||
main(){
|
void main(){
|
||||||
test('for dart grammar tests', () {
|
test('for dart grammar tests', () {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -208,5 +208,112 @@ void main() {
|
||||||
expect(result, closeTo(9.8596, 0.0001));
|
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');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue