Error handling

This commit is contained in:
Your Name 2026-02-09 16:57:53 +01:00
parent 0d63043251
commit 77f62396e0
7 changed files with 122 additions and 17 deletions

View file

@ -11,3 +11,11 @@
- See `./Makefile` for more examples. - See `./Makefile` for more examples.
# Workflow
- One feature at a time
- Create a git branch for each new feature
- After making changes, and before consider the feature is implemented
- Allways pass all the tests and integration tests
- Build the application for linux and web-server
- Launch the apllication for web-server, with a timeout of 60s
- Dont merge the feature branch into master, the work will be reviewed by a human.

View file

@ -6,6 +6,7 @@ import 'package:markdown/markdown.dart' as markdown;
import '../formula_models.dart'; import '../formula_models.dart';
import '../formula_evaluator.dart'; import '../formula_evaluator.dart';
import '../corpus.dart'; import '../corpus.dart';
import '../error_handler.dart';
import 'unit_dropdown.dart'; import 'unit_dropdown.dart';
class FormulaScreen extends StatefulWidget { class FormulaScreen extends StatefulWidget {
@ -36,9 +37,8 @@ class D4rtEditingController extends TextEditingController {
_lastError = null; _lastError = null;
return true; return true;
} catch (e, s) { } catch (e, s) {
errorHandler.notify(e, s);
_lastError = e.toString(); _lastError = e.toString();
print("validate: $text: $e");
print("stack: $s");
return false; return false;
} }
} }
@ -95,8 +95,6 @@ class _FormulaScreenState extends State<FormulaScreen> {
} }
void _evaluateFormula() { void _evaluateFormula() {
print( "EVALUATE FORMULA");
try { try {
final inputValues = <String, dynamic>{}; final inputValues = <String, dynamic>{};
for (final input in widget.formula.input) { for (final input in widget.formula.input) {
@ -159,12 +157,10 @@ class _FormulaScreenState extends State<FormulaScreen> {
setState(() {}); setState(() {});
} catch (e, stack) { } catch (e, stack) {
debugPrint('Formula evaluation error: $e'); errorHandler.notify(e, 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()}'),
backgroundColor: Theme.of(context).colorScheme.error, backgroundColor: Theme.of(context).colorScheme.error,
), ),
); );

View file

@ -154,12 +154,8 @@ class Corpus{
return ret; return ret;
} }
catch( e2, stack2 ){ catch( e2, stack2 ){
print(completeSourceExpression); errorHandler.notify(e1.toString() + "\n" + completeSourceExpression, stack1);
print(e1); errorHandler.notify(e2.toString() + "\n" + completeSourceStatement, stack2);
print(stack1);
print(completeSourceStatement);
print(e2);
print(stack2);
throw FormulaEvaluationException( "Evaluation as statement and expression failed" ); throw FormulaEvaluationException( "Evaluation as statement and expression failed" );
} }
} }

View file

@ -1,8 +1,9 @@
/// A library for working with mathematical formulas using the d4rt interpreter. /// A library for working with mathematical formulas using the d4rt interpreter.
/// ///
/// This library provides data models for representing formulas and an evaluator /// This library provides data models for representing formulas and an evaluator
/// for executing them using the d4rt Dart interpreter. /// for executing them using the d4rt Dart interpreter.
library; library;
export 'formula_models.dart'; export 'formula_models.dart';
export 'formula_evaluator.dart'; export 'formula_evaluator.dart';
export 'error_handler.dart';

44
lib/error_handler.dart Normal file
View file

@ -0,0 +1,44 @@
/// Centralized error handler that gets notified of every caught exception
class ErrorHandler {
/// Singleton instance of ErrorHandler
static final ErrorHandler _instance = ErrorHandler._internal();
factory ErrorHandler() => _instance;
ErrorHandler._internal();
/// Callback function to handle errors - can be overridden for custom behavior
void Function(Object error, [StackTrace? stackTrace])? onError;
/// Notifies the error handler of an exception
void notify(Object error, [StackTrace? stackTrace]) {
// Print the exception to stdout as requested
print('ErrorHandler caught exception:');
print(error);
if (stackTrace != null) {
print('Stack trace:');
print(stackTrace);
}
// Call the custom error handler if provided
onError?.call(error, stackTrace);
}
/// Convenience method to wrap code that might throw exceptions
T handleError<T>(T Function() operation, {T? defaultValue}) {
try {
return operation();
} catch (error, stackTrace) {
notify(error, stackTrace);
if (defaultValue != null) {
return defaultValue;
}
rethrow;
}
}
}
/// Global instance of ErrorHandler for easy access
final ErrorHandler errorHandler = ErrorHandler();

View file

@ -2,6 +2,7 @@ import 'dart:math' as Math;
import 'package:d4rt/d4rt.dart'; import 'package:d4rt/d4rt.dart';
import 'formula_models.dart'; import 'formula_models.dart';
import 'error_handler.dart';
@ -105,8 +106,7 @@ class FormulaEvaluator {
return result; return result;
} }
catch (e, stack) { catch (e, stack) {
print( "Error evaluating formula source:\n$completeSource" ); errorHandler.notify(e.toString() + "\n" + completeSource, stack);
print( stack );
throw FormulaEvaluationException( throw FormulaEvaluationException(
'Error evaluating formula "${formula.name}": $e', 'Error evaluating formula "${formula.name}": $e',
e, e,

View file

@ -0,0 +1,60 @@
import 'package:d4rt_formulas/error_handler.dart';
import 'package:test/test.dart';
void main() {
group('ErrorHandler', () {
test('should print exceptions to stdout', () {
final errors = <Object>[];
final stacks = <StackTrace?>[];
// Capture errors instead of printing them
errorHandler.onError = (error, [stackTrace]) {
errors.add(error);
stacks.add(stackTrace);
};
// Simulate an exception being caught
try {
throw Exception('Test exception');
} catch (e, s) {
errorHandler.notify(e, s);
}
expect(errors.length, 1);
expect(errors.first.toString(), 'Exception: Test exception');
expect(stacks.length, 1);
});
test('should handle errors in handleError method', () {
final errors = <Object>[];
errorHandler.onError = (error, [stackTrace]) {
errors.add(error);
};
int result = errorHandler.handleError(() => 42, defaultValue: 0);
expect(result, 42);
result = errorHandler.handleError(() {
throw Exception('Handled exception');
}, defaultValue: 100);
expect(result, 100);
expect(errors.length, 1);
});
test('should rethrow exceptions when no default value provided', () {
final errors = <Object>[];
errorHandler.onError = (error, [stackTrace]) {
errors.add(error);
};
expect(() {
errorHandler.handleError(() {
throw Exception('Rethrown exception');
});
}, throwsA(const TypeMatcher<Exception>()));
expect(errors.length, 1);
});
});
}