Error handling
This commit is contained in:
parent
0d63043251
commit
77f62396e0
7 changed files with 122 additions and 17 deletions
|
|
@ -11,3 +11,11 @@
|
|||
- 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.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import 'package:markdown/markdown.dart' as markdown;
|
|||
import '../formula_models.dart';
|
||||
import '../formula_evaluator.dart';
|
||||
import '../corpus.dart';
|
||||
import '../error_handler.dart';
|
||||
import 'unit_dropdown.dart';
|
||||
|
||||
class FormulaScreen extends StatefulWidget {
|
||||
|
|
@ -36,9 +37,8 @@ class D4rtEditingController extends TextEditingController {
|
|||
_lastError = null;
|
||||
return true;
|
||||
} catch (e, s) {
|
||||
errorHandler.notify(e, s);
|
||||
_lastError = e.toString();
|
||||
print("validate: $text: $e");
|
||||
print("stack: $s");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -95,8 +95,6 @@ class _FormulaScreenState extends State<FormulaScreen> {
|
|||
}
|
||||
|
||||
void _evaluateFormula() {
|
||||
print( "EVALUATE FORMULA");
|
||||
|
||||
try {
|
||||
final inputValues = <String, dynamic>{};
|
||||
for (final input in widget.formula.input) {
|
||||
|
|
@ -159,12 +157,10 @@ class _FormulaScreenState extends State<FormulaScreen> {
|
|||
|
||||
setState(() {});
|
||||
} catch (e, stack) {
|
||||
debugPrint('Formula evaluation error: $e');
|
||||
debugPrint('Stack trace: $stack');
|
||||
|
||||
errorHandler.notify(e, stack);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Error: ${e.toString()}\n${stack.toString()}'),
|
||||
content: Text('Error: ${e.toString()}'),
|
||||
backgroundColor: Theme.of(context).colorScheme.error,
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -154,12 +154,8 @@ class Corpus{
|
|||
return ret;
|
||||
}
|
||||
catch( e2, stack2 ){
|
||||
print(completeSourceExpression);
|
||||
print(e1);
|
||||
print(stack1);
|
||||
print(completeSourceStatement);
|
||||
print(e2);
|
||||
print(stack2);
|
||||
errorHandler.notify(e1.toString() + "\n" + completeSourceExpression, stack1);
|
||||
errorHandler.notify(e2.toString() + "\n" + completeSourceStatement, stack2);
|
||||
throw FormulaEvaluationException( "Evaluation as statement and expression failed" );
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/// A library for working with mathematical formulas using the d4rt interpreter.
|
||||
///
|
||||
///
|
||||
/// This library provides data models for representing formulas and an evaluator
|
||||
/// for executing them using the d4rt Dart interpreter.
|
||||
library;
|
||||
|
||||
export 'formula_models.dart';
|
||||
export 'formula_evaluator.dart';
|
||||
export 'error_handler.dart';
|
||||
|
|
|
|||
44
lib/error_handler.dart
Normal file
44
lib/error_handler.dart
Normal 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();
|
||||
|
|
@ -2,6 +2,7 @@ import 'dart:math' as Math;
|
|||
|
||||
import 'package:d4rt/d4rt.dart';
|
||||
import 'formula_models.dart';
|
||||
import 'error_handler.dart';
|
||||
|
||||
|
||||
|
||||
|
|
@ -105,8 +106,7 @@ class FormulaEvaluator {
|
|||
return result;
|
||||
}
|
||||
catch (e, stack) {
|
||||
print( "Error evaluating formula source:\n$completeSource" );
|
||||
print( stack );
|
||||
errorHandler.notify(e.toString() + "\n" + completeSource, stack);
|
||||
throw FormulaEvaluationException(
|
||||
'Error evaluating formula "${formula.name}": $e',
|
||||
e,
|
||||
|
|
|
|||
60
test/error_handler_test.dart
Normal file
60
test/error_handler_test.dart
Normal 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);
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
Reference in a new issue