added fpdart demo
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
# https://dart.dev/guides/libraries/private-files
|
||||
# Created by `dart pub`
|
||||
.dart_tool/
|
||||
@@ -0,0 +1 @@
|
||||
none
|
||||
@@ -0,0 +1,44 @@
|
||||
# **🚀 Demo-Projekt: AppError und Funktionale Programmierung mit fpdart**
|
||||
|
||||
Dieses Demo-Projekt begleitet die Zwischenpräsentation und verdeutlicht, wie funktionale Programmierung mit Dart und der Bibliothek `fpdart` umgesetzt werden kann. Es greift die zentralen Konzepte der Präsentation auf.
|
||||
|
||||
Das Projekt zeigt, wie durch funktionale Ansätze mit `fpdart`:
|
||||
|
||||
- ✅ Logik deklarativ ausgedrückt wird.
|
||||
- 🛠️ Fehler elegant und strukturiert behandelt werden.
|
||||
- 🔄 Erweiterbare, wartbare und typsichere Programme entstehen.
|
||||
|
||||
## **🔑 Zentrale Aspekte**
|
||||
|
||||
### **1. Monaden als Datenkonstrukte**
|
||||
|
||||
- 📦 Anwendung von **`Either`** für synchrone Fehler- und Erfolgsverarbeitung.
|
||||
- ⏳ Verwendung von **`TaskEither`** zur Kombination von Lazy Evaluation mit asynchroner Verarbeitung und Fehlerbehandlung.
|
||||
|
||||
### **2. 🛡️ `AppError`: Einheitliche Fehlerstruktur**
|
||||
|
||||
- Einführung eines stark typisierten `AppError`, um Fehler systematisch zu kategorisieren (z. B. `ValidationError`, `DatabaseError`, `NetworkError`).
|
||||
- Klare Trennung von:
|
||||
- 📄 **Nachricht** (für Benutzer)
|
||||
- ⚙️ **Typ** (zur Kategorisierung)
|
||||
- 🔍 **Details** (für Debugging)
|
||||
|
||||
### **3. Praxisnahe Beispiele**
|
||||
|
||||
- 🔍 **Validierung**: Prüfung von Benutzereingaben mit `Either`.
|
||||
- 🛠️ **Fehlerbehandlung**: Nutzung von `TaskEither` für Datenbank- und Netzwerkfehler.
|
||||
- 🔗 **Verkettung von Funktionen**:
|
||||
- Nahtlose Kombination von Validierung, Speicherung und weiteren Prozessen.
|
||||
- Kein Abbruch bei Zwischenfehlern.
|
||||
|
||||
### **4. Verbindung zu funktionalen Konzepten**
|
||||
|
||||
- 🏛️ **Ursprung**: Konzepte aus Haskell und FP-TS.
|
||||
- 🌀 **Monaden**: Praktische Anwendung zur sicheren Datenverarbeitung ohne Seiteneffekte.
|
||||
- 🌐 **Anwendungsbezug**: Funktionale Programmierung als Werkzeug für robuste und skalierbare Software.
|
||||
|
||||
Das Projekt dient als praktische Grundlage, um die in der Präsentation behandelten Konzepte von funktionaler Programmierung und Fehlerbehandlung greifbar zu machen. Es zeigt, wie mit `fpdart`:
|
||||
|
||||
- Der Code sauber und wartbar bleibt.
|
||||
- Funktionale Programmierung in Dart effektiv umgesetzt wird.
|
||||
- Fehlermanagement nicht nur robust, sondern auch elegant sein kann.
|
||||
@@ -0,0 +1,30 @@
|
||||
# This file configures the static analysis results for your project (errors,
|
||||
# warnings, and lints).
|
||||
#
|
||||
# This enables the 'recommended' set of lints from `package:lints`.
|
||||
# This set helps identify many issues that may lead to problems when running
|
||||
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
|
||||
# style and format.
|
||||
#
|
||||
# If you want a smaller set of lints you can change this to specify
|
||||
# 'package:lints/core.yaml'. These are just the most critical lints
|
||||
# (the recommended set includes the core lints).
|
||||
# The core lints are also what is used by pub.dev for scoring packages.
|
||||
|
||||
include: package:lints/recommended.yaml
|
||||
|
||||
# Uncomment the following section to specify additional rules.
|
||||
|
||||
# linter:
|
||||
# rules:
|
||||
# - camel_case_types
|
||||
|
||||
# analyzer:
|
||||
# exclude:
|
||||
# - path/to/excluded/files/**
|
||||
|
||||
# For more information about the core and recommended set of lints, see
|
||||
# https://dart.dev/go/core-lints
|
||||
|
||||
# For additional information about configuring this file, see
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
@@ -0,0 +1,46 @@
|
||||
import 'package:fpdart/fpdart.dart';
|
||||
|
||||
// Fehlerkategorien
|
||||
enum AppErrorType {
|
||||
ValidationError,
|
||||
DatabaseError,
|
||||
NetworkError,
|
||||
UnknownError,
|
||||
}
|
||||
|
||||
class AppError {
|
||||
final String message; // Benutzerfreundliche Fehlermeldung
|
||||
final AppErrorType type; // Typisierte Fehlerkategorie
|
||||
final Exception? exception; // Originale Exception (falls vorhanden)
|
||||
|
||||
AppError({
|
||||
required this.message,
|
||||
this.type = AppErrorType.UnknownError,
|
||||
this.exception,
|
||||
});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AppError(message: $message, type: $type, exception: $exception)';
|
||||
}
|
||||
|
||||
/// Hilfsmethode zur einfachen Erstellung eines `Left`-Werts für `Either`
|
||||
static Either<AppError, T> left<T>(
|
||||
String message, {
|
||||
AppErrorType? type,
|
||||
Exception? exception,
|
||||
}) {
|
||||
return Either.left(AppError(
|
||||
message: message,
|
||||
type: type ?? AppErrorType.UnknownError,
|
||||
exception: exception,
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is AppError && other.message == message && other.type == type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import 'package:demo/app_error.dart';
|
||||
import 'package:fpdart/fpdart.dart';
|
||||
|
||||
// Mock-Datenbank
|
||||
final existingEmails = ["existing@example.com"];
|
||||
|
||||
// Validierungsfunktionen
|
||||
Either<AppError, String> validateName(String name) {
|
||||
return name.isNotEmpty
|
||||
? Either.right(name)
|
||||
: AppError.left(
|
||||
"Name cannot be empty",
|
||||
type: AppErrorType.ValidationError,
|
||||
);
|
||||
}
|
||||
|
||||
Either<AppError, String> validateEmail(String email) {
|
||||
final emailRegex = RegExp(r"^[a-zA-Z0-9.]+@[a-zA-Z0-9]+\.[a-zA-Z]+");
|
||||
return emailRegex.hasMatch(email)
|
||||
? Either.right(email)
|
||||
: AppError.left(
|
||||
"Invalid email format",
|
||||
type: AppErrorType.ValidationError,
|
||||
);
|
||||
}
|
||||
|
||||
// Asynchrone Überprüfung, ob die E-Mail bereits existiert
|
||||
TaskEither<AppError, bool> checkEmailExists(String email) {
|
||||
return TaskEither.tryCatch(
|
||||
() async => existingEmails.contains(email),
|
||||
(error, _) => AppError(
|
||||
message: "Error checking email existence",
|
||||
type: AppErrorType.DatabaseError,
|
||||
exception: error as Exception?,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Benutzer in der Datenbank speichern (Dummy-Implementierung)
|
||||
TaskEither<AppError, bool> saveUser(String name, String email) {
|
||||
return TaskEither.tryCatch(
|
||||
() async {
|
||||
await Future.delayed(Duration(seconds: 1)); // Simulierte Latenz
|
||||
print("User saved: $name, $email");
|
||||
return true;
|
||||
},
|
||||
(error, _) => AppError(
|
||||
message: "Error saving user",
|
||||
type: AppErrorType.DatabaseError,
|
||||
exception: error as Exception?,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Optional: Begrüßungsnachricht senden
|
||||
TaskEither<AppError, bool> sendWelcomeEmail(String email) {
|
||||
return TaskEither.tryCatch(
|
||||
() async {
|
||||
print("Welcome email sent to $email");
|
||||
return true;
|
||||
},
|
||||
(error, _) => AppError(
|
||||
message: "Error sending welcome email",
|
||||
type: AppErrorType.NetworkError,
|
||||
exception: error as Exception?,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
_fe_analyzer_shared:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: "45cfa8471b89fb6643fe9bf51bd7931a76b8f5ec2d65de4fb176dba8d4f22c77"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "73.0.0"
|
||||
_macros:
|
||||
dependency: transitive
|
||||
description: dart
|
||||
source: sdk
|
||||
version: "0.3.2"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: "4959fec185fe70cce007c57e9ab6983101dbe593d2bf8bbfb4453aaec0cf470a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.8.0"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.0"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.12.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.19.1"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: convert
|
||||
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
coverage:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: coverage
|
||||
sha256: "4b03e11f6d5b8f6e5bb5e9f7889a56fe6c5cbe942da5378ea4d4d7f73ef9dfe5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.0"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: crypto
|
||||
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.6"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file
|
||||
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
fpdart:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: fpdart
|
||||
sha256: "1b84ce64453974159f08046f5d05592020d1fcb2099d7fe6ec58da0e7337af77"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: frontend_server_client
|
||||
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: glob
|
||||
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_multi_server
|
||||
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.1"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "76d306a1c3afb33fe82e2bbacad62a61f409b5634c915fceb0d799de1a913360"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.1"
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: io
|
||||
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.1"
|
||||
lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: lints
|
||||
sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logging
|
||||
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
macros:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: macros
|
||||
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.2-main.4"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.16+1"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.16.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mime
|
||||
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
node_preamble:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: node_preamble
|
||||
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_config
|
||||
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.1"
|
||||
pool:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pool
|
||||
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.1"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pub_semver
|
||||
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf
|
||||
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.2"
|
||||
shelf_packages_handler:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_packages_handler
|
||||
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
shelf_static:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_static
|
||||
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.3"
|
||||
shelf_web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_web_socket
|
||||
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
source_map_stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_map_stack_trace
|
||||
sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
source_maps:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_maps
|
||||
sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.10.12"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.0"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.12.0"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
sha256: "0bd04f5bb74fcd6ff0606a888a30e917af9bd52820b178eaa464beb11dca84b6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
test:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: test
|
||||
sha256: f2a018e2baa6fce7c8daa55b8bdf4b3d7d165f82caac269e4cbe5edd666c0e4c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.25.9"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.4"
|
||||
test_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_core
|
||||
sha256: "60ff490bb383858015df7b7a0d883301a426edf9033989f55f091d91efb9dfaf"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.6"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: typed_data
|
||||
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
vm_service:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.3.1"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: watcher
|
||||
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket
|
||||
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.6"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
webkit_inspection_protocol:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webkit_inspection_protocol
|
||||
sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: yaml
|
||||
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
sdks:
|
||||
dart: ">=3.5.4 <4.0.0"
|
||||
@@ -0,0 +1,16 @@
|
||||
name: demo
|
||||
description: A sample command-line application.
|
||||
version: 1.0.0
|
||||
# repository: https://github.com/my_org/my_repo
|
||||
|
||||
environment:
|
||||
sdk: ^3.5.4
|
||||
|
||||
# Add regular dependencies here.
|
||||
dependencies:
|
||||
fpdart: ^1.1.1
|
||||
# path: ^1.8.0
|
||||
|
||||
dev_dependencies:
|
||||
lints: ^4.0.0
|
||||
test: ^1.24.0
|
||||
@@ -0,0 +1,137 @@
|
||||
import 'package:demo/app_error.dart';
|
||||
import 'package:demo/demo.dart';
|
||||
import 'package:fpdart/fpdart.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group("User Registration Tests", () {
|
||||
test("Valid name and email results in successful registration", () async {
|
||||
final name = "John Doe";
|
||||
final email = "newuser@example.com";
|
||||
|
||||
final result =
|
||||
await Either<AppError, (String, String)>.right((name, email))
|
||||
.flatMap((userData) => validateName(userData.$1).flatMap(
|
||||
(validName) => validateEmail(userData.$2)
|
||||
.map((validEmail) => (validName, validEmail))))
|
||||
.toTaskEither()
|
||||
.flatMap((validUser) => checkEmailExists(validUser.$2).flatMap(
|
||||
(exists) => exists
|
||||
? AppError.left("Email already exists",
|
||||
type: AppErrorType.ValidationError)
|
||||
.toTaskEither()
|
||||
: saveUser(validUser.$1, validUser.$2)))
|
||||
.flatMap((_) => sendWelcomeEmail(email))
|
||||
.run();
|
||||
|
||||
result.match(
|
||||
(error) => fail("Test failed with error: ${error.message}"),
|
||||
(success) => expect(success, equals(true)),
|
||||
);
|
||||
});
|
||||
|
||||
test("Invalid email format returns validation error", () async {
|
||||
final name = "John Doe";
|
||||
final email = "invalid-email";
|
||||
|
||||
final result =
|
||||
await Either<AppError, (String, String)>.right((name, email))
|
||||
.flatMap((userData) => validateName(userData.$1).flatMap(
|
||||
(validName) => validateEmail(userData.$2)
|
||||
.map((validEmail) => (validName, validEmail))))
|
||||
.toTaskEither()
|
||||
.run();
|
||||
|
||||
result.match(
|
||||
(error) {
|
||||
expect(error.message, equals("Invalid email format"));
|
||||
expect(error.type, equals(AppErrorType.ValidationError));
|
||||
},
|
||||
(success) => fail("Test succeeded unexpectedly"),
|
||||
);
|
||||
});
|
||||
|
||||
test("Existing email results in error", () async {
|
||||
final name = "John Doe";
|
||||
final email = "existing@example.com";
|
||||
|
||||
final result =
|
||||
await Either<AppError, (String, String)>.right((name, email))
|
||||
.flatMap((userData) => validateName(userData.$1).flatMap(
|
||||
(validName) => validateEmail(userData.$2)
|
||||
.map((validEmail) => (validName, validEmail))))
|
||||
.toTaskEither()
|
||||
.flatMap((validUser) => checkEmailExists(validUser.$2).flatMap(
|
||||
(exists) => exists
|
||||
? AppError.left("Email already exists",
|
||||
type: AppErrorType.ValidationError)
|
||||
.toTaskEither()
|
||||
: saveUser(validUser.$1, validUser.$2)))
|
||||
.run();
|
||||
|
||||
result.match(
|
||||
(error) => expect(error.message, equals("Email already exists")),
|
||||
(success) => fail("Test succeeded unexpectedly"),
|
||||
);
|
||||
});
|
||||
|
||||
test("Empty name returns validation error", () async {
|
||||
final name = "";
|
||||
final email = "newuser@example.com";
|
||||
|
||||
final result =
|
||||
await Either<AppError, (String, String)>.right((name, email))
|
||||
.flatMap((userData) => validateName(userData.$1).flatMap(
|
||||
(validName) => validateEmail(userData.$2)
|
||||
.map((validEmail) => (validName, validEmail))))
|
||||
.toTaskEither()
|
||||
.run();
|
||||
|
||||
result.match(
|
||||
(error) => expect(
|
||||
error,
|
||||
equals(AppError(
|
||||
message: "Name cannot be empty",
|
||||
type: AppErrorType.ValidationError))),
|
||||
(success) => fail("Test succeeded unexpectedly"),
|
||||
);
|
||||
});
|
||||
|
||||
test("Error while sending welcome email is handled gracefully", () async {
|
||||
final name = "John Doe";
|
||||
final email = "newuser@example.com";
|
||||
|
||||
// Simuliere einen Fehler beim Senden der Begrüßungs-E-Mail
|
||||
TaskEither<AppError, bool> sendWelcomeEmail(String email) {
|
||||
return TaskEither.left(AppError(
|
||||
message: "Error sending welcome email",
|
||||
type: AppErrorType.NetworkError,
|
||||
));
|
||||
}
|
||||
|
||||
final result =
|
||||
await Either<AppError, (String, String)>.right((name, email))
|
||||
.flatMap((userData) => validateName(userData.$1).flatMap(
|
||||
(validName) => validateEmail(userData.$2)
|
||||
.map((validEmail) => (validName, validEmail))))
|
||||
.toTaskEither()
|
||||
.flatMap((validUser) =>
|
||||
checkEmailExists(validUser.$2).flatMap((exists) => exists
|
||||
? AppError.left(
|
||||
"Email already exists",
|
||||
type: AppErrorType.ValidationError,
|
||||
).toTaskEither()
|
||||
: saveUser(validUser.$1, validUser.$2)))
|
||||
.flatMap((_) => sendWelcomeEmail(email))
|
||||
.run();
|
||||
|
||||
result.match(
|
||||
(error) {
|
||||
expect(error.message, equals("Error sending welcome email"));
|
||||
expect(error.type, equals(AppErrorType.NetworkError));
|
||||
},
|
||||
(success) => fail("Test succeeded unexpectedly"),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user