├── .github └── workflows │ ├── dart-cd.yml │ └── dart-ci.yml ├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── example ├── README.md ├── cpf_validator.dart ├── pubspec.lock └── pubspec.yaml ├── lib ├── functions.dart ├── result_dart.dart └── src │ ├── async_result.dart │ ├── result_dart_base.dart │ ├── result_extension.dart │ ├── types.dart │ └── unit.dart ├── pubspec.lock ├── pubspec.yaml └── test └── src ├── async_result_test.dart ├── result_dart_base_test.dart ├── result_extension_test.dart └── result_test.dart /.github/workflows/dart-cd.yml: -------------------------------------------------------------------------------- 1 | name: Dart CI 2 | on: 3 | push: 4 | tags: 5 | - 'v*' 6 | 7 | jobs: 8 | upload-to-pubdev: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | 13 | - uses: dart-lang/setup-dart@v1.3 14 | with: 15 | sdk: 2.17.5 16 | - name: Install dependencies 17 | run: dart pub get 18 | 19 | - name: Analyze project source 20 | run: dart analyze 21 | 22 | - name: Run tests 23 | run: dart test 24 | 25 | - name: '>> PUBLISH <<' 26 | uses: k-paxian/dart-package-publisher@master 27 | with: 28 | credentialJson: ${{ secrets.CREDENTIAL_JSON }} 29 | -------------------------------------------------------------------------------- /.github/workflows/dart-ci.yml: -------------------------------------------------------------------------------- 1 | name: Dart CI 2 | on: 3 | pull_request: 4 | branches: 5 | - 'main' 6 | 7 | jobs: 8 | upload-to-pubdev: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | 13 | - uses: dart-lang/setup-dart@v1.3 14 | with: 15 | sdk: 2.17.5 16 | - name: Install dependencies 17 | run: dart pub get 18 | 19 | - name: Analyze project source 20 | run: dart analyze 21 | 22 | - name: Install coverage 23 | run: dart pub global activate coverage 24 | 25 | - name: Run tests with coverage 26 | run: dart pub global run coverage:test_with_coverage 27 | 28 | - name: Report code coverage 29 | uses: zgosalvez/github-actions-report-lcov@v2 30 | with: 31 | coverage-files: coverage/lcov.info 32 | minimum-coverage: 100 33 | artifact-name: code-coverage-report 34 | github-token: ${{ secrets.GIT_TOKEN }} 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | build/ 32 | 33 | # Android related 34 | **/android/**/gradle-wrapper.jar 35 | **/android/.gradle 36 | **/android/captures/ 37 | **/android/gradlew 38 | **/android/gradlew.bat 39 | **/android/local.properties 40 | **/android/**/GeneratedPluginRegistrant.java 41 | 42 | # iOS/XCode related 43 | **/ios/**/*.mode1v3 44 | **/ios/**/*.mode2v3 45 | **/ios/**/*.moved-aside 46 | **/ios/**/*.pbxuser 47 | **/ios/**/*.perspectivev3 48 | **/ios/**/*sync/ 49 | **/ios/**/.sconsign.dblite 50 | **/ios/**/.tags* 51 | **/ios/**/.vagrant/ 52 | **/ios/**/DerivedData/ 53 | **/ios/**/Icon? 54 | **/ios/**/Pods/ 55 | **/ios/**/.symlinks/ 56 | **/ios/**/profile 57 | **/ios/**/xcuserdata 58 | **/ios/.generated/ 59 | **/ios/Flutter/App.framework 60 | **/ios/Flutter/Flutter.framework 61 | **/ios/Flutter/Flutter.podspec 62 | **/ios/Flutter/Generated.xcconfig 63 | **/ios/Flutter/app.flx 64 | **/ios/Flutter/app.zip 65 | **/ios/Flutter/flutter_assets/ 66 | **/ios/Flutter/flutter_export_environment.sh 67 | **/ios/ServiceDefinitions.json 68 | **/ios/Runner/GeneratedPluginRegistrant.* 69 | 70 | # Exceptions to above rules. 71 | !**/ios/**/default.mode1v3 72 | !**/ios/**/default.mode2v3 73 | !**/ios/**/default.pbxuser 74 | !**/ios/**/default.perspectivev3 75 | 76 | coverage/ 77 | .vscode/ 78 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 8962f6dc68ec8e2206ac2fa874da4a453856c7d3 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [2.1.0] - 2025-04-10 2 | 3 | - Added `pureFold` and `mapFold` operators. 4 | 5 | ## [2.0.0] - 2024-12-11 6 | 7 | - This version aims to reduce the `Result` boilerplate by making the `Failure` type Exception by default. This will free the Result from having to type `Failure`, making the declaration smaller. 8 | 9 | If there is a need to type `Failure`, use `ResultDart`. 10 | 11 | ### Added 12 | - Introduced `typedef` for `Result` and `AsyncResult` to simplify usage: 13 | - `Result` is a simplified alias for `ResultDart`. 14 | - `AsyncResult` is a simplified alias for `AsyncResultDart`. 15 | 16 | ### Changed 17 | - Replaced `Result` class with `ResultDart` as the base class for all results. 18 | - Default failure type for `ResultDart` is now `Exception`. 19 | - This change reduces boilerplate and improves usability by eliminating the need to specify the failure type explicitly in most cases. 20 | 21 | ### Removed 22 | 23 | - Remove factories `Result.success` and `Result.failure`. 24 | 25 | 26 | ### Migration Guide 27 | - In version >=2.0.0, the Failure typing is by default an `Exception`, but if there is a need to type it, use `ResultDart`. 28 | 29 | only `Success` type: 30 | ```dart 31 | // Old 32 | Result myResult = Success(42); 33 | 34 | // NEW 35 | Result myResult = Success(42); 36 | 37 | ``` 38 | 39 | with `Success` and `Failure` types: 40 | ```dart 41 | // Old 42 | Result myResult = Success(42); 43 | 44 | // NEW 45 | ResultDart myResult = Success(42); 46 | 47 | ``` 48 | 49 | 50 | ## [1.1.1] - 2023-07-05 51 | 52 | * pump Dart version to 3.0.0 53 | * fix: factory const 54 | 55 | ## [1.1.0] - 2023-07-05 56 | 57 | * feat: Added onSuccess and onFailure callbacks 58 | 59 | ## [1.0.6] - 2023-05-11 60 | 61 | * feat: Dart 3.0.0 support 62 | 63 | ## [1.0.5] - 2023-01-26 64 | 65 | * feat: Added FutureOr in AsyncResult.MapError 66 | 67 | ## [1.0.4] - 2023-01-26 68 | 69 | * feat: Added FutureOr in AsyncResult.Map 70 | 71 | ## [1.0.3] - 2022-12-22 72 | 73 | * fix: AsyncResult recover 74 | 75 | ## [1.0.2] - 2022-12-18 76 | 77 | * fix: separed functions.dart import 78 | 79 | ## [1.0.1] - 2022-12-17 80 | 81 | * fix: recover operator return a `Result` instead a `Failure`. 82 | 83 | ## [1.0.0+2] - 2022-12-16 84 | 85 | * Initial release 86 | 87 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Flutterando 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

RESULT_DART

5 | 6 | 7 |
8 | 12 | 13 |

14 | This package aims to create an implemetation of Kotlin's and Swift's Result class and own operators. 15 | Inspired by `multiple_result` package, the `dartz` package and the `fpdart` package. 16 |
17 | 18 | Explore the docs » 19 |
20 |
21 | 22 | Report Bug 23 | · 24 | Request Feature 25 |

26 | 27 |
28 | 29 |
30 | 31 | [![Version](https://img.shields.io/github/v/release/Flutterando/result_dart?style=plastic)](https://pub.dev/packages/result_dart) 32 | [![Pub Points](https://img.shields.io/pub/points/result_dart?label=pub%20points&style=plastic)](https://pub.dev/packages/result_dart/score) 33 | [![Flutterando Analysis](https://img.shields.io/badge/style-flutterando__analysis-blueviolet?style=plastic)](https://pub.dev/packages/flutterando_analysis/) 34 | 35 | [![Pub Publisher](https://img.shields.io/pub/publisher/result_dart?style=plastic)](https://pub.dev/publishers/flutterando.com.br/packages) 36 | 37 | 38 |
39 | 40 |
41 | 42 | --- 43 | 44 | 45 |
46 | Table of Contents 47 |
    48 |
  1. About The Project
  2. 49 | m
  3. Getting Started
  4. 50 |
  5. How to Use
  6. 51 |
  7. Features
  8. 52 |
  9. Contributing
  10. 53 |
  11. Contact
  12. 54 |
  13. Acknowledgements
  14. 55 |
56 |
57 | 58 | --- 59 | 60 |
61 | 62 | 63 | ## About The Project 64 | 65 | 66 | 67 | 68 |
69 | 72 | 73 |
74 | 75 | 76 | 77 | Overruns are common in design, and modern architectures always designate a place to handle failures. 78 | This means dramatically decreasing try/catch usage and keeping treatments in one place. 79 | But the other layers of code need to know about the two main values `[Success, Failure]`. The solution lies in the 80 | `Result` class pattern implemented in `Kotlin` and `Swift` and now also in `Dart` via this package(`result_dart`). 81 | 82 | This project is distributed under the MIT License. See `LICENSE` for more information. 83 | 84 | 85 |

(back to top)

86 | 87 | 88 | ## Migrate 1.1.1 to 2.0.0 89 | 90 | This version aims to reduce the `Result` boilerplate by making the `Failure` type Exception by default. This will free the Result from having to type `Failure`, making the declaration smaller. 91 | 92 | ```dart 93 | // Old 94 | Result myResult = Success(42); 95 | 96 | // NEW 97 | Result myResult = Success(42); 98 | 99 | ``` 100 | 101 | if there is a need to type it, use `ResultDart`: 102 | 103 | ```dart 104 | // Old 105 | Result myResult = Success(42); 106 | 107 | // NEW 108 | ResultDart myResult = Success(42); 109 | 110 | ``` 111 | 112 | 113 | 114 | ## Getting Started 115 | 116 | 117 | To get `result_dart` working in your project follow either of the instructions below: 118 | 119 | a) Add `result_dart` as a dependency in your Pubspec.yaml: 120 | ```yaml 121 | dependencies: 122 | result_dart: x.x.x 123 | ``` 124 | 125 | b) Use Dart Pub: 126 | ``` 127 | dart pub add result_dart 128 | ``` 129 | 130 |
131 | 132 | 133 | ## How to Use 134 | 135 | 136 | In the return of a function that you want to receive an answer as Sucess or Failure, set it to return a Result type; 137 | 138 | ```dart 139 | Result getSomethingPretty(); 140 | ``` 141 | 142 | then add the Success and the Failure types. 143 | 144 | ```dart 145 | Result getSomethingPretty() { 146 | 147 | } 148 | 149 | ``` 150 | 151 | In the return of the above function, you just need to use: 152 | ```dart 153 | // Using Normal instance 154 | return Success('Something Pretty'); 155 | 156 | // import 'package:result_dart/functions.dart' 157 | return successOf('Something Pretty'); 158 | 159 | // Using extensions 160 | return 'Something Pretty'.toSuccess(); 161 | ``` 162 | 163 | or 164 | 165 | ```dart 166 | // Using Normal instance 167 | return Failure(Exception('something ugly happened...')); 168 | 169 | // import 'package:result_dart/functions.dart' 170 | return failureOf('Something Pretty'); 171 | 172 | // Using extensions 173 | return 'something ugly happened...'.toFailure(); 174 | ``` 175 | 176 | The function should look something like this: 177 | 178 | ```dart 179 | 180 | Result getSomethingPretty() { 181 | if(isOk) { 182 | return Success('OK!'); 183 | } else { 184 | return Failure(Exception('Not Ok!')); 185 | } 186 | } 187 | 188 | ``` 189 | or when using extensions, like this: 190 | 191 | ```dart 192 | 193 | Result getSomethingPretty() { 194 | if(isOk) { 195 | return 'OK!'.toSuccess(); 196 | } else { 197 | return Exception('Not Ok!').toFailure(); 198 | } 199 | } 200 | 201 | ``` 202 | 203 | > IMPORTANT NOTE: The `toSuccess()` and `toFailure()` methods cannot be used on a `Result` object or a `Future`. If you try, will be throw a Assertion exception. 204 | 205 |
206 | 207 | #### Handling the Result with `fold`: 208 | 209 | Returns the result of onSuccess for the encapsulated value 210 | if this instance represents `Success` or the result of onError function 211 | for the encapsulated value if it is `Failure`. 212 | 213 | ```dart 214 | void main() { 215 | final result = getSomethingPretty(); 216 | final String message = result.fold( 217 | (success) { 218 | // handle the success here 219 | return "success"; 220 | }, 221 | (failure) { 222 | // handle the failure here 223 | return "failure"; 224 | }, 225 | ); 226 | 227 | } 228 | ``` 229 | 230 | #### Handling the Result with `getOrThrow` 231 | 232 | Returns the success value as a throwing expression. 233 | 234 | ```dart 235 | void main() { 236 | final result = getSomethingPretty(); 237 | 238 | try { 239 | final value = result.getOrThrow(); 240 | } on Exception catch(e){ 241 | // e 242 | } 243 | } 244 | 245 | ``` 246 | 247 | #### Handling the Result with `getOrNull` 248 | 249 | Returns the value of [Success] or null. 250 | 251 | ```dart 252 | void main() { 253 | final result = getSomethingPretty(); 254 | result.getOrNull(); 255 | } 256 | 257 | ``` 258 | 259 | #### Handling the Result with `getOrElse` 260 | 261 | Returns the encapsulated value if this instance represents `Success` 262 | or the result of `onFailure` function for 263 | the encapsulated a `Failure` value. 264 | 265 | ```dart 266 | void main() { 267 | final result = getSomethingPretty(); 268 | result.getOrElse((failure) => 'OK'); 269 | } 270 | 271 | ``` 272 | 273 | #### Handling the Result with `getOrDefault` 274 | 275 | Returns the encapsulated value if this instance represents 276 | `Success` or the `defaultValue` if it is `Failure`. 277 | 278 | ```dart 279 | void main() { 280 | final result = getSomethingPretty(); 281 | result.getOrDefault('OK'); 282 | } 283 | 284 | ``` 285 | 286 | 287 | #### Handling the Result with `exceptionOrNull` 288 | 289 | Returns the value of [Failure] or null. 290 | 291 | ```dart 292 | void main() { 293 | final result = getSomethingPretty(); 294 | result.exceptionOrNull(); 295 | } 296 | ``` 297 | 298 | ### Transforming a Result 299 | 300 | #### Mapping success value with `map` 301 | 302 | Returns a new `Result`, mapping any `Success` value 303 | using the given transformation. 304 | 305 | ```dart 306 | void main() { 307 | final result = getResult() 308 | .map((e) => MyObject.fromMap(e)); 309 | 310 | result.getOrNull(); //Instance of 'MyObject' 311 | } 312 | ``` 313 | 314 | #### Mapping failure value with `mapError` 315 | 316 | Returns a new `Result`, mapping any `Error` value 317 | using the given transformation. 318 | 319 | ```dart 320 | void main() { 321 | final result = getResult() 322 | .mapError((e) => MyException(e)); 323 | 324 | result.exceptionOrNull(); //Instance of 'MyException' 325 | 326 | } 327 | ``` 328 | 329 | #### Chain others [Result] by any `Success` value with `flatMap` 330 | 331 | 332 | Returns a new `Result`, mapping any `Success` value 333 | using the given transformation and unwrapping the produced `Result`. 334 | 335 | ```dart 336 | 337 | Result checkIsEven(String input){ 338 | if(input % 2 == 0){ 339 | return Success(input); 340 | } else { 341 | return Failure(MyException('isn`t even!')); 342 | } 343 | } 344 | 345 | void main() { 346 | final result = getNumberResult() 347 | .flatMap((s) => checkIsEven(s)); 348 | } 349 | ``` 350 | #### Chain others [Result] by `Failure` value with `flatMapError` 351 | 352 | 353 | Returns a new `Result`, mapping any `Error` value 354 | using the given transformation and unwrapping the produced `Result`. 355 | 356 | ```dart 357 | 358 | void main() { 359 | final result = getNumberResult() 360 | .flatMapError((e) => checkError(e)); 361 | } 362 | ``` 363 | 364 | #### Resolve [Result] by `Failure` value with `recover` 365 | 366 | Returns the encapsulated `Result` of the given transform function 367 | applied to the encapsulated a `Failure` or the original 368 | encapsulated value if it is success. 369 | 370 | ```dart 371 | 372 | void main() { 373 | final result = getNumberResult() 374 | .recover((f) => Success('Resolved!')); 375 | } 376 | ``` 377 | 378 | #### Add a pure `Success` value with `pure` 379 | 380 | Change the [Success] value. 381 | 382 | ```dart 383 | void main() { 384 | final result = getSomethingPretty().pure(10); 385 | 386 | String? mySuccessResult; 387 | if (result.isSuccess()) { 388 | mySuccessResult = result.getOrNull(); // 10 389 | } 390 | } 391 | ``` 392 | 393 | #### Add a pure `Failure` value with `pureError` 394 | 395 | Change the [Failure] value. 396 | 397 | ```dart 398 | void main() { 399 | final result = getSomethingPretty().pureError(10); 400 | if (result.isFailure()) { 401 | result.exceptionOrNull(); // 10 402 | } 403 | } 404 | ``` 405 | #### Swap a `Result` with `swap` 406 | 407 | Swap the values contained inside the [Success] and [Failure] 408 | of this [Result]. 409 | 410 | ```dart 411 | void main() { 412 | Result result =...; 413 | Result newResult = result.swap(); 414 | } 415 | ``` 416 | 417 | ### Unit Type 418 | 419 | Some results do not need a specific return. Use the Unit type to signal an **empty** return. 420 | 421 | ```dart 422 | Result 423 | ``` 424 | 425 | ### Help with functions that return their parameter: 426 | 427 | NOTE: use import 'package:result_dart/functions.dart' 428 | 429 | 430 | Sometimes it is necessary to return the parameter of the function as in this example: 431 | 432 | ```dart 433 | final result = Success(0); 434 | 435 | String value = result.when((s) => '$s', (e) => e); 436 | print(string) // "0"; 437 | ``` 438 | 439 | We can use the `identity` function or its acronym `id` to facilitate the declaration of this type of function that returns its own parameter and does nothing else: 440 | 441 | ```dart 442 | final result = Success(0); 443 | 444 | // changed `(e) => e` by `id` 445 | String value = result.when((s) => '$s', id); 446 | print(string) // "0"; 447 | ``` 448 | 449 | ### Use **AsyncResult** type: 450 | 451 | `AsyncResult` represents an asynchronous computation. 452 | Use this component when working with asynchronous **Result**. 453 | 454 | **AsyncResult** has some of the operators of the **Result** object to perform data transformations (**Success** or **Failure**) before executing the Future. 455 | 456 | All **Result** operators is available in **AsyncResult** 457 | 458 | `AsyncResult` is a **typedef** of `Future>`. 459 | 460 | ```dart 461 | 462 | AsyncResult fetchProducts() async { 463 | try { 464 | final response = await dio.get('/products'); 465 | final products = ProductModel.fromList(response.data); 466 | return Success(products); 467 | } on DioError catch (e) { 468 | return Failure(ProductException(e.message)); 469 | } 470 | } 471 | 472 | ... 473 | 474 | final state = await fetch() 475 | .map((products) => LoadedState(products)) 476 | .mapLeft((failure) => ErrorState(failure)) 477 | 478 | ``` 479 |
480 | 481 | 482 | 483 | 484 | 485 |

(back to top)

486 | 487 | 488 | 489 | 491 | ## Features 492 | 493 | - ✅ Result implementation. 494 | - ✅ Result`s operators(map, flatMap, mapError, flatMapError, swap, when, fold, getOrNull, exceptionOrNull, isSuccess, isError). 495 | - ✅ AsyncResult implementation. 496 | - ✅ AsyncResult`s operators(map, flatMap, mapError, flatMapError, swap, when, fold, getOrNull, exceptionOrNull, isSuccess, isError). 497 | - ✅ Auxiliar functions (id, identity, success, failure). 498 | - ✅ Unit type. 499 | 500 |

(back to top)

501 | 502 | 503 | 504 | 505 | ## Contributing 506 | 507 | Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. 508 | 509 | If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the appropriate tag. 510 | Don't forget to give the project a star! Thanks again! 511 | 512 | 1. Fork the Project 513 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 514 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) 515 | 4. Push to the Branch (`git push origin feature/AmazingFeature`) 516 | 5. Open a Pull Request 517 | 518 | Remember to include a tag, and to follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) and [Semantic Versioning](https://semver.org/) when uploading your commit and/or creating the issue. 519 | 520 |

(back to top)

521 | 522 | 523 | 524 | 525 | ## Contact 526 | 527 | Flutterando Community 528 | - [Discord](https://discord.flutterando.com.br/) 529 | - [Telegram](https://t.me/flutterando) 530 | - [Website](https://www.flutterando.com.br) 531 | - [Youtube Channel](https://www.youtube.com.br/flutterando) 532 | - [Other useful links](https://linktr.ee/flutterando) 533 | 534 | 535 |

(back to top)

536 | 537 | 538 | ## Acknowledgements 539 | 540 | 541 | Thank you to all the people who contributed to this project, whithout you this project would not be here today. 542 | 543 |
544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 |

(back to top)

553 | 554 | 555 | ## Maintaned by 556 | 557 |
558 |

559 | 560 | 561 | 562 |

563 | Built and maintained by Flutterando. 564 |

565 |

566 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutterando_analysis/flutter_package.yaml 2 | 3 | linter: 4 | rules: 5 | avoid_catches_without_on_clauses: false 6 | use_setters_to_change_properties: false 7 | only_throw_errors: false -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # example 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /example/cpf_validator.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:result_dart/result_dart.dart'; 4 | 5 | void main(List args) { 6 | final result = getTerminalInput() // 7 | .map(removeSpecialCharacteres) 8 | .flatMap(parseNumbers) 9 | .map(validateCPF); 10 | 11 | print('CPF Validator: ${result.isSuccess()}'); 12 | } 13 | 14 | Result getTerminalInput() { 15 | final text = stdin.readLineSync(); 16 | if (text == null || text.isEmpty) { 17 | return const Failure(ValidatorException('Incorrect input')); 18 | } 19 | 20 | return Success(text); 21 | } 22 | 23 | String removeSpecialCharacteres(String input) { 24 | final reg = RegExp(r'(\D)'); 25 | return input.replaceAll(reg, ''); 26 | } 27 | 28 | Result> parseNumbers(String input) { 29 | if (input.isEmpty) { 30 | return const Failure(ValidatorException('Input is Empty')); 31 | } 32 | 33 | try { 34 | final list = input.split('').map(int.parse).toList(); 35 | return Success(list); 36 | } catch (e) { 37 | return const Failure(ValidatorException('Parse error')); 38 | } 39 | } 40 | 41 | bool validateCPF(List numberDigits) { 42 | final secondRef = numberDigits.removeLast(); 43 | final secondDigit = calculateDigit(numberDigits); 44 | if (secondRef != secondDigit) { 45 | return false; 46 | } 47 | 48 | final firstRef = numberDigits.removeLast(); 49 | final firstDigit = calculateDigit(numberDigits); 50 | return firstRef == firstDigit; 51 | } 52 | 53 | int calculateDigit(List digits) { 54 | final digitSum = sumDigits(digits.reversed.toList()); 55 | final rest = digitSum % 11; 56 | if (rest < 2) { 57 | return 0; 58 | } else { 59 | return 11 - rest; 60 | } 61 | } 62 | 63 | int sumDigits(List digits) { 64 | var multiplier = 2; 65 | var sum = 0; 66 | for (var d = 0; d < digits.length; d++, multiplier++) { 67 | sum += digits[d] * multiplier; 68 | } 69 | return sum; 70 | } 71 | 72 | class ValidatorException implements Exception { 73 | final String message; 74 | const ValidatorException(this.message); 75 | } 76 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | meta: 5 | dependency: transitive 6 | description: 7 | name: meta 8 | sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "1.9.1" 12 | result_dart: 13 | dependency: "direct main" 14 | description: 15 | path: ".." 16 | relative: true 17 | source: path 18 | version: "1.1.0" 19 | sdks: 20 | dart: ">=3.0.0 <4.0.0" 21 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: A new Flutter project. 3 | publish_to: 'none' 4 | version: 1.0.0+1 5 | 6 | environment: 7 | sdk: ">=3.0.0 <4.0.0" 8 | 9 | dependencies: 10 | result_dart: 11 | path: ../ 12 | -------------------------------------------------------------------------------- /lib/functions.dart: -------------------------------------------------------------------------------- 1 | library result_dart; 2 | 3 | import 'package:result_dart/result_dart.dart'; 4 | 5 | /// Returns the given `a`. 6 | /// 7 | /// Same as `id`. 8 | /// 9 | /// Shortcut function to return the input parameter: 10 | /// ```dart 11 | /// final result = Result.success(10); 12 | /// 13 | /// /// Without using `identity`, you must write a function to return 14 | /// /// the input parameter `(error) => error`. 15 | /// final noId = result.when((success) => '$success', (error) => error); 16 | /// 17 | /// /// Using `identity`/`id`, the function just returns its input parameter. 18 | /// final withIdentity = result.when((success) => '$success', identity); 19 | /// final withId = result.when((success) => '$success', identity); 20 | /// ``` 21 | T identity(T a) => a; 22 | 23 | /// Returns the given `a`. 24 | /// 25 | /// Same as `identity`. 26 | /// 27 | /// Shortcut function to return the input parameter: 28 | /// ```dart 29 | /// final result = Result.success(10); 30 | /// 31 | /// /// Without using `identity`, you must write a function to return 32 | /// /// the input parameter `(error) => error`. 33 | /// final noId = result.when((success) => '$success', (error) => error); 34 | /// 35 | /// /// Using `identity`/`id`, the function just returns its input parameter. 36 | /// final withIdentity = result.when((success) => '$success', id); 37 | /// final withId = result.when((success) => '$success', id); 38 | /// ``` 39 | T id(T a) => a; 40 | 41 | /// Build a [Result] that returns a [Failure]. 42 | ResultDart successOf(S success) { 43 | return Success(success); 44 | } 45 | 46 | /// Build a [Result] that returns a [Failure]. 47 | ResultDart failureOf(F failure) { 48 | return Failure(failure); 49 | } 50 | -------------------------------------------------------------------------------- /lib/result_dart.dart: -------------------------------------------------------------------------------- 1 | library result_dart; 2 | 3 | export 'src/async_result.dart'; 4 | export 'src/result_dart_base.dart'; 5 | export 'src/result_extension.dart'; 6 | export 'src/types.dart'; 7 | export 'src/unit.dart'; 8 | -------------------------------------------------------------------------------- /lib/src/async_result.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import '../result_dart.dart'; 4 | 5 | /// `AsyncResultDart` represents an asynchronous computation. 6 | typedef AsyncResultDart = Future>; 7 | 8 | /// `AsyncResultDart` represents an asynchronous computation. 9 | extension AsyncResultDartExtension // 10 | on AsyncResultDart { 11 | /// Returns a new `Result`, mapping any `Success` value 12 | /// using the given transformation and unwrapping the produced `Result`. 13 | AsyncResultDart flatMap( 14 | FutureOr> Function(S success) fn, 15 | ) { 16 | return then((result) => result.fold(fn, Failure.new)); 17 | } 18 | 19 | /// Returns a new `Result`, mapping any `Error` value 20 | /// using the given transformation and unwrapping the produced `Result`. 21 | AsyncResultDart flatMapError( 22 | FutureOr> Function(F error) fn, 23 | ) { 24 | return then((result) => result.fold(Success.new, fn)); 25 | } 26 | 27 | /// Returns a new `AsyncResultDart`, mapping any `Success` value 28 | /// using the given transformation. 29 | AsyncResultDart map( 30 | FutureOr Function(S success) fn, 31 | ) { 32 | return then( 33 | (result) => result.map(fn).fold( 34 | (success) async { 35 | return Success(await success); 36 | }, 37 | (failure) { 38 | return Failure(failure); 39 | }, 40 | ), 41 | ); 42 | } 43 | 44 | /// Returns a new `Result`, mapping any `Error` value 45 | /// using the given transformation. 46 | AsyncResultDart mapError( 47 | FutureOr Function(F error) fn, 48 | ) { 49 | return then( 50 | (result) => result.mapError(fn).fold( 51 | (success) { 52 | return Success(success); 53 | }, 54 | (failure) async { 55 | return Failure(await failure); 56 | }, 57 | ), 58 | ); 59 | } 60 | 61 | /// Change a [Success] value. 62 | AsyncResultDart pure(W success) { 63 | return then((result) => result.pure(success)); 64 | } 65 | 66 | /// Change the [Failure] value. 67 | AsyncResultDart pureError(W error) { 68 | return mapError((_) => error); 69 | } 70 | 71 | /// Swap the values contained inside the [Success] and [Failure] 72 | /// of this [AsyncResultDart]. 73 | AsyncResultDart swap() { 74 | return then((result) => result.swap()); 75 | } 76 | 77 | /// Returns the Future result of onSuccess for the encapsulated value 78 | /// if this instance represents `Success` or the result of onError function 79 | /// for the encapsulated value if it is `Error`. 80 | Future fold( 81 | W Function(S success) onSuccess, 82 | W Function(F error) onError, 83 | ) { 84 | return then((result) => result.fold(onSuccess, onError)); 85 | } 86 | 87 | /// Returns the future value of [S] if any. 88 | Future getOrNull() { 89 | return then((result) => result.getOrNull()); 90 | } 91 | 92 | /// Returns the future value of [F] if any. 93 | Future exceptionOrNull() { 94 | return then((result) => result.exceptionOrNull()); 95 | } 96 | 97 | /// Returns true if the current result is an [Failure]. 98 | Future isError() { 99 | return then((result) => result.isError()); 100 | } 101 | 102 | /// Returns true if the current result is a [Success]. 103 | Future isSuccess() { 104 | return then((result) => result.isSuccess()); 105 | } 106 | 107 | /// Returns the success value as a throwing expression. 108 | Future getOrThrow() { 109 | return then((result) => result.getOrThrow()); 110 | } 111 | 112 | /// Returns the encapsulated value if this instance represents `Success` 113 | /// or the result of `onFailure` function for 114 | /// the encapsulated a `Failure` value. 115 | Future getOrElse(S Function(F) onFailure) { 116 | return then((result) => result.getOrElse(onFailure)); 117 | } 118 | 119 | /// Returns the encapsulated value if this instance represents 120 | /// `Success` or the `defaultValue` if it is `Failure`. 121 | Future getOrDefault(S defaultValue) { 122 | return then((result) => result.getOrDefault(defaultValue)); 123 | } 124 | 125 | /// Returns the encapsulated `Result` of the given transform function 126 | /// applied to the encapsulated a `Failure` or the original 127 | /// encapsulated value if it is success. 128 | AsyncResultDart recover( 129 | FutureOr> Function(F failure) onFailure, 130 | ) { 131 | return then((result) => result.fold(Success.new, onFailure)); 132 | } 133 | 134 | /// Performs the given action on the encapsulated Throwable 135 | /// exception if this instance represents failure. 136 | /// Returns the original Result unchanged. 137 | AsyncResultDart onFailure(void Function(F failure) onFailure) { 138 | return then((result) => result.onFailure(onFailure)); 139 | } 140 | 141 | /// Performs the given action on the encapsulated value if this 142 | /// instance represents success. Returns the original Result unchanged. 143 | AsyncResultDart onSuccess(void Function(S success) onSuccess) { 144 | return then((result) => result.onSuccess(onSuccess)); 145 | } 146 | 147 | /// Returns the encapsulated value if this instance represents `Success` 148 | /// or the result of `onFailure` function for 149 | /// the encapsulated a `Failure` value. 150 | AsyncResultDart pureFold( 151 | G success, 152 | W failure, 153 | ) { 154 | return then((result) => result.pureFold(success, failure)); 155 | } 156 | 157 | /// Returns the encapsulated value if this instance represents `Success` 158 | /// or the result of `onFailure` function for 159 | /// the encapsulated a `Failure` value. 160 | AsyncResultDart mapFold( 161 | G Function(S success) onSuccess, 162 | W Function(F error) onError, 163 | ) { 164 | return then((result) => result.mapFold(onSuccess, onError)); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /lib/src/result_dart_base.dart: -------------------------------------------------------------------------------- 1 | import 'package:meta/meta.dart'; 2 | import 'package:result_dart/result_dart.dart'; 3 | 4 | import 'unit.dart' as type_unit; 5 | 6 | /// Base Result class 7 | /// 8 | /// Receives two values [F] and [S] 9 | /// as [F] is an error and [S] is a success. 10 | sealed class ResultDart { 11 | /// Returns the success value as a throwing expression. 12 | S getOrThrow(); 13 | 14 | /// Returns the encapsulated value if this instance represents `Success` 15 | /// or the result of `onFailure` function for 16 | /// the encapsulated a `Failure` value. 17 | S getOrElse(S Function(F failure) onFailure); 18 | 19 | /// Returns the encapsulated value if this instance represents 20 | /// `Success` or the `defaultValue` if it is `Failure`. 21 | S getOrDefault(S defaultValue); 22 | 23 | /// Returns the value of [Success] or null. 24 | S? getOrNull(); 25 | 26 | /// Returns the value of [Failure] or null. 27 | F? exceptionOrNull(); 28 | 29 | /// Returns true if the current result is an [Failure]. 30 | bool isError(); 31 | 32 | /// Returns true if the current result is a [Success]. 33 | bool isSuccess(); 34 | 35 | /// Returns the result of onSuccess for the encapsulated value 36 | /// if this instance represents `Success` or the result of onError function 37 | /// for the encapsulated value if it is `Failure`. 38 | W fold( 39 | W Function(S success) onSuccess, 40 | W Function(F failure) onFailure, 41 | ); 42 | 43 | /// Performs the given action on the encapsulated value if this 44 | /// instance represents success. Returns the original Result unchanged. 45 | ResultDart onSuccess( 46 | void Function(S success) onSuccess, 47 | ); 48 | 49 | /// Performs the given action on the encapsulated Throwable 50 | /// exception if this instance represents failure. 51 | /// Returns the original Result unchanged. 52 | ResultDart onFailure( 53 | void Function(F failure) onFailure, 54 | ); 55 | 56 | /// Returns a new `Result`, mapping any `Success` value 57 | /// using the given transformation. 58 | ResultDart map(W Function(S success) fn); 59 | 60 | /// Returns a new `Result`, mapping any `Error` value 61 | /// using the given transformation. 62 | ResultDart mapError(W Function(F error) fn); 63 | 64 | /// Returns a new `Result`, mapping any `Success` value 65 | /// using the given transformation and unwrapping the produced `Result`. 66 | ResultDart flatMap( 67 | ResultDart Function(S success) fn, 68 | ); 69 | 70 | /// Returns a new `Result`, mapping any `Error` value 71 | /// using the given transformation and unwrapping the produced `Result`. 72 | ResultDart flatMapError( 73 | ResultDart Function(F error) fn, 74 | ); 75 | 76 | /// Change the [Success] value. 77 | ResultDart pure(W success); 78 | 79 | /// Change the [Failure] value. 80 | ResultDart pureError(W error); 81 | 82 | /// Return a [AsyncResult]. 83 | AsyncResultDart toAsyncResult(); 84 | 85 | /// Swap the values contained inside the [Success] and [Failure] 86 | /// of this [Result]. 87 | ResultDart swap(); 88 | 89 | /// Returns the encapsulated `Result` of the given transform function 90 | /// applied to the encapsulated a `Failure` or the original 91 | /// encapsulated value if it is success. 92 | ResultDart recover( 93 | ResultDart Function(F failure) onFailure, 94 | ); 95 | 96 | /// Returns a new `Result`, mapping any `Success` value 97 | /// using the given transformation and unwrapping the produced `Result`. 98 | /// Returns a new `Result`, mapping any `Error` value 99 | /// using the given transformation and unwrapping the produced `Result`. 100 | ResultDart pureFold( 101 | G success, 102 | W failure, 103 | ); 104 | 105 | /// Returns a new `Result`, mapping any `Success` value 106 | /// using the given transformation and unwrapping the produced `Result`. 107 | /// Returns a new `Result`, mapping any `Error` value 108 | /// using the given transformation and unwrapping the produced `Result`. 109 | ResultDart mapFold( 110 | G Function(S success) onSuccess, 111 | W Function(F failure) onFailure, 112 | ); 113 | } 114 | 115 | /// Success Result. 116 | /// 117 | /// return it when the result of a [Result] is 118 | /// the expected value. 119 | @immutable 120 | final class Success // 121 | implements 122 | ResultDart { 123 | /// Receives the [S] param as 124 | /// the successful result. 125 | const Success( 126 | this._success, 127 | ); 128 | 129 | /// Build a `Success` with `Unit` value. 130 | /// ```dart 131 | /// Success.unit() == Success(unit) 132 | /// ``` 133 | static Success unit() { 134 | return Success(type_unit.unit); 135 | } 136 | 137 | final S _success; 138 | 139 | @override 140 | bool isError() => false; 141 | 142 | @override 143 | bool isSuccess() => true; 144 | 145 | @override 146 | int get hashCode => _success.hashCode; 147 | 148 | @override 149 | bool operator ==(Object other) { 150 | return other is Success && other._success == _success; 151 | } 152 | 153 | @override 154 | W fold( 155 | W Function(S success) onSuccess, 156 | W Function(F error) onFailure, 157 | ) { 158 | return onSuccess(_success); 159 | } 160 | 161 | @override 162 | F? exceptionOrNull() => null; 163 | 164 | @override 165 | S getOrNull() => _success; 166 | 167 | @override 168 | ResultDart flatMap( 169 | ResultDart Function(S success) fn, 170 | ) { 171 | return fn(_success); 172 | } 173 | 174 | @override 175 | ResultDart flatMapError( 176 | ResultDart Function(F failure) fn, 177 | ) { 178 | return Success(_success); 179 | } 180 | 181 | @override 182 | ResultDart swap() { 183 | return Failure(_success); 184 | } 185 | 186 | @override 187 | S getOrThrow() { 188 | return _success; 189 | } 190 | 191 | @override 192 | S getOrElse(S Function(F failure) onFailure) { 193 | return _success; 194 | } 195 | 196 | @override 197 | S getOrDefault(S defaultValue) => _success; 198 | 199 | @override 200 | ResultDart map(W Function(S success) fn) { 201 | final newSuccess = fn(_success); 202 | return Success(newSuccess); 203 | } 204 | 205 | @override 206 | ResultDart mapError(W Function(F error) fn) { 207 | return Success(_success); 208 | } 209 | 210 | @override 211 | ResultDart pure(W success) { 212 | return map((_) => success); 213 | } 214 | 215 | @override 216 | ResultDart pureError(W error) { 217 | return Success(_success); 218 | } 219 | 220 | @override 221 | ResultDart recover( 222 | ResultDart Function(F failure) onFailure, 223 | ) { 224 | return Success(_success); 225 | } 226 | 227 | @override 228 | AsyncResultDart toAsyncResult() async => this; 229 | 230 | @override 231 | ResultDart onFailure(void Function(F failure) onFailure) { 232 | return this; 233 | } 234 | 235 | @override 236 | ResultDart onSuccess(void Function(S success) onSuccess) { 237 | onSuccess(_success); 238 | return this; 239 | } 240 | 241 | @override 242 | ResultDart mapFold( 243 | G Function(S success) onSuccess, 244 | W Function(F failure) onFailure, 245 | ) { 246 | return fold( 247 | (s) => Success(onSuccess(s)), 248 | (f) => Failure(onFailure(f)), 249 | ); 250 | } 251 | 252 | @override 253 | ResultDart pureFold( 254 | G success, 255 | W failure, 256 | ) { 257 | return fold( 258 | (s) => Success(success), 259 | (f) => Failure(failure), 260 | ); 261 | } 262 | } 263 | 264 | /// Error Result. 265 | /// 266 | /// return it when the result of a [ResultDart] is 267 | /// not the expected value. 268 | @immutable 269 | final class Failure // 270 | implements 271 | ResultDart { 272 | /// Receives the [F] param as 273 | /// the error result. 274 | const Failure(this._failure); 275 | 276 | /// Build a `Failure` with `Unit` value. 277 | /// ```dart 278 | /// Failure.unit() == Failure(unit) 279 | /// ``` 280 | static Failure unit() { 281 | return Failure(type_unit.unit); 282 | } 283 | 284 | final F _failure; 285 | 286 | @override 287 | bool isError() => true; 288 | 289 | @override 290 | bool isSuccess() => false; 291 | 292 | @override 293 | int get hashCode => _failure.hashCode; 294 | 295 | @override 296 | bool operator ==(Object other) => // 297 | other is Failure && other._failure == _failure; 298 | 299 | @override 300 | W fold( 301 | W Function(S succcess) onSuccess, 302 | W Function(F failure) onFailure, 303 | ) { 304 | return onFailure(_failure); 305 | } 306 | 307 | @override 308 | F exceptionOrNull() => _failure; 309 | 310 | @override 311 | S? getOrNull() => null; 312 | 313 | @override 314 | ResultDart flatMap( 315 | ResultDart Function(S success) fn, 316 | ) { 317 | return Failure(_failure); 318 | } 319 | 320 | @override 321 | ResultDart flatMapError( 322 | ResultDart Function(F failure) fn, 323 | ) { 324 | return fn(_failure); 325 | } 326 | 327 | @override 328 | ResultDart swap() { 329 | return Success(_failure); 330 | } 331 | 332 | @override 333 | S getOrThrow() { 334 | throw _failure; 335 | } 336 | 337 | @override 338 | S getOrElse(S Function(F failure) onFailure) { 339 | return onFailure(_failure); 340 | } 341 | 342 | @override 343 | S getOrDefault(S defaultValue) => defaultValue; 344 | 345 | @override 346 | ResultDart map(W Function(S success) fn) { 347 | return Failure(_failure); 348 | } 349 | 350 | @override 351 | ResultDart mapError(W Function(F failure) fn) { 352 | final newFailure = fn(_failure); 353 | return Failure(newFailure); 354 | } 355 | 356 | @override 357 | ResultDart pure(W success) { 358 | return Failure(_failure); 359 | } 360 | 361 | @override 362 | ResultDart pureError(W error) { 363 | return mapError((failure) => error); 364 | } 365 | 366 | @override 367 | ResultDart recover( 368 | ResultDart Function(F failure) onFailure, 369 | ) { 370 | return onFailure(_failure); 371 | } 372 | 373 | @override 374 | AsyncResultDart toAsyncResult() async => this; 375 | 376 | @override 377 | ResultDart onFailure(void Function(F failure) onFailure) { 378 | onFailure(_failure); 379 | return this; 380 | } 381 | 382 | @override 383 | ResultDart onSuccess(void Function(S success) onSuccess) { 384 | return this; 385 | } 386 | 387 | @override 388 | ResultDart mapFold( 389 | G Function(S success) onSuccess, 390 | W Function(F failure) onFailure, 391 | ) { 392 | return fold( 393 | (s) => Success(onSuccess(s)), 394 | (f) => Failure(onFailure(f)), 395 | ); 396 | } 397 | 398 | @override 399 | ResultDart pureFold( 400 | G success, 401 | W failure, 402 | ) { 403 | return fold( 404 | (s) => Success(success), 405 | (f) => Failure(failure), 406 | ); 407 | } 408 | } 409 | -------------------------------------------------------------------------------- /lib/src/result_extension.dart: -------------------------------------------------------------------------------- 1 | import '../result_dart.dart'; 2 | 3 | /// Adds methods for converting any object 4 | /// into a `Result` type (`Success` or `Failure`). 5 | extension ResultObjectExtension on W { 6 | /// Convert the object to a `Result` type [Failure]. 7 | /// 8 | /// Will throw an error if used on a `Result` or `Future` instance. 9 | Failure toFailure() { 10 | assert( 11 | this is! ResultDart, 12 | 'Don`t use the "toError()" method ' 13 | 'on instances of the Result.', 14 | ); 15 | assert( 16 | this is! Future, 17 | 'Don`t use the "toError()" method ' 18 | 'on instances of the Future.', 19 | ); 20 | 21 | return Failure(this); 22 | } 23 | 24 | /// Convert the object to a `Result` type [Success]. 25 | /// 26 | /// Will throw an error if used on a `Result` or `Future` instance. 27 | Success toSuccess() { 28 | assert( 29 | this is! ResultDart, 30 | 'Don`t use the "toSuccess()" method ' 31 | 'on instances of the Result.', 32 | ); 33 | assert( 34 | this is! Future, 35 | 'Don`t use the "toSuccess()" method ' 36 | 'on instances of the Future.', 37 | ); 38 | return Success(this); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/types.dart: -------------------------------------------------------------------------------- 1 | import 'package:result_dart/result_dart.dart'; 2 | 3 | /// A typedef for a `Result` that simplifies the usage of `ResultDart` 4 | /// with `Exception` as the default failure type. 5 | /// 6 | /// This is used to represent operations that can succeed with a 7 | /// value of type `S` 8 | /// or fail with an `Exception`. 9 | typedef Result = ResultDart; 10 | 11 | /// A typedef for an asynchronous `Result`, simplifying the usage 12 | /// of `AsyncResultDart` 13 | /// with `Exception` as the default failure type. 14 | /// 15 | /// This is used to represent asynchronous operations that can succeed 16 | /// with a value of type `S` 17 | /// or fail with an `Exception`. 18 | typedef AsyncResult = AsyncResultDart; 19 | -------------------------------------------------------------------------------- /lib/src/unit.dart: -------------------------------------------------------------------------------- 1 | import 'package:meta/meta.dart'; 2 | 3 | /// Used instead of `void` as a return statement for a function 4 | /// when no value is to be returned. 5 | /// 6 | /// There is only one value of type [Unit]. 7 | @sealed 8 | class Unit { 9 | const Unit._(); 10 | } 11 | 12 | /// Used instead of `void` as a return statement for a function when 13 | /// no value is to be returned. 14 | const unit = Unit._(); 15 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | _fe_analyzer_shared: 5 | dependency: transitive 6 | description: 7 | name: _fe_analyzer_shared 8 | sha256: "0816708f5fbcacca324d811297153fe3c8e047beb5c6752e12292d2974c17045" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "62.0.0" 12 | analyzer: 13 | dependency: transitive 14 | description: 15 | name: analyzer 16 | sha256: "21862995c9932cd082f89d72ae5f5e2c110d1a0204ad06e4ebaee8307b76b834" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "6.0.0" 20 | args: 21 | dependency: transitive 22 | description: 23 | name: args 24 | sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "2.4.2" 28 | async: 29 | dependency: transitive 30 | description: 31 | name: async 32 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "2.11.0" 36 | boolean_selector: 37 | dependency: transitive 38 | description: 39 | name: boolean_selector 40 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "2.1.1" 44 | collection: 45 | dependency: transitive 46 | description: 47 | name: collection 48 | sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.17.2" 52 | convert: 53 | dependency: transitive 54 | description: 55 | name: convert 56 | sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "3.1.1" 60 | coverage: 61 | dependency: transitive 62 | description: 63 | name: coverage 64 | sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097" 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "1.6.3" 68 | crypto: 69 | dependency: transitive 70 | description: 71 | name: crypto 72 | sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab 73 | url: "https://pub.dev" 74 | source: hosted 75 | version: "3.0.3" 76 | dart_internal: 77 | dependency: transitive 78 | description: 79 | name: dart_internal 80 | sha256: "781e0d03812e5b52fdc3f71540b178245021be64d22cbc88da2aee6b45705183" 81 | url: "https://pub.dev" 82 | source: hosted 83 | version: "0.2.13" 84 | file: 85 | dependency: transitive 86 | description: 87 | name: file 88 | sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" 89 | url: "https://pub.dev" 90 | source: hosted 91 | version: "7.0.0" 92 | flutterando_analysis: 93 | dependency: "direct dev" 94 | description: 95 | name: flutterando_analysis 96 | sha256: "9541b7d6c849f3f82c8ac4f65116c8c4371d37ad691e6d6da905325707aa6244" 97 | url: "https://pub.dev" 98 | source: hosted 99 | version: "0.0.2" 100 | frontend_server_client: 101 | dependency: transitive 102 | description: 103 | name: frontend_server_client 104 | sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" 105 | url: "https://pub.dev" 106 | source: hosted 107 | version: "3.2.0" 108 | glob: 109 | dependency: transitive 110 | description: 111 | name: glob 112 | sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" 113 | url: "https://pub.dev" 114 | source: hosted 115 | version: "2.1.2" 116 | http_multi_server: 117 | dependency: transitive 118 | description: 119 | name: http_multi_server 120 | sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" 121 | url: "https://pub.dev" 122 | source: hosted 123 | version: "3.2.1" 124 | http_parser: 125 | dependency: transitive 126 | description: 127 | name: http_parser 128 | sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" 129 | url: "https://pub.dev" 130 | source: hosted 131 | version: "4.0.2" 132 | io: 133 | dependency: transitive 134 | description: 135 | name: io 136 | sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" 137 | url: "https://pub.dev" 138 | source: hosted 139 | version: "1.0.4" 140 | js: 141 | dependency: transitive 142 | description: 143 | name: js 144 | sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 145 | url: "https://pub.dev" 146 | source: hosted 147 | version: "0.6.7" 148 | logging: 149 | dependency: transitive 150 | description: 151 | name: logging 152 | sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" 153 | url: "https://pub.dev" 154 | source: hosted 155 | version: "1.2.0" 156 | matcher: 157 | dependency: transitive 158 | description: 159 | name: matcher 160 | sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" 161 | url: "https://pub.dev" 162 | source: hosted 163 | version: "0.12.16" 164 | meta: 165 | dependency: "direct main" 166 | description: 167 | name: meta 168 | sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" 169 | url: "https://pub.dev" 170 | source: hosted 171 | version: "1.9.1" 172 | mime: 173 | dependency: transitive 174 | description: 175 | name: mime 176 | sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e 177 | url: "https://pub.dev" 178 | source: hosted 179 | version: "1.0.4" 180 | node_preamble: 181 | dependency: transitive 182 | description: 183 | name: node_preamble 184 | sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" 185 | url: "https://pub.dev" 186 | source: hosted 187 | version: "2.0.2" 188 | package_config: 189 | dependency: transitive 190 | description: 191 | name: package_config 192 | sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" 193 | url: "https://pub.dev" 194 | source: hosted 195 | version: "2.1.0" 196 | path: 197 | dependency: transitive 198 | description: 199 | name: path 200 | sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" 201 | url: "https://pub.dev" 202 | source: hosted 203 | version: "1.8.3" 204 | pool: 205 | dependency: transitive 206 | description: 207 | name: pool 208 | sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" 209 | url: "https://pub.dev" 210 | source: hosted 211 | version: "1.5.1" 212 | pub_semver: 213 | dependency: transitive 214 | description: 215 | name: pub_semver 216 | sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" 217 | url: "https://pub.dev" 218 | source: hosted 219 | version: "2.1.4" 220 | shelf: 221 | dependency: transitive 222 | description: 223 | name: shelf 224 | sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 225 | url: "https://pub.dev" 226 | source: hosted 227 | version: "1.4.1" 228 | shelf_packages_handler: 229 | dependency: transitive 230 | description: 231 | name: shelf_packages_handler 232 | sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" 233 | url: "https://pub.dev" 234 | source: hosted 235 | version: "3.0.2" 236 | shelf_static: 237 | dependency: transitive 238 | description: 239 | name: shelf_static 240 | sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e 241 | url: "https://pub.dev" 242 | source: hosted 243 | version: "1.1.2" 244 | shelf_web_socket: 245 | dependency: transitive 246 | description: 247 | name: shelf_web_socket 248 | sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" 249 | url: "https://pub.dev" 250 | source: hosted 251 | version: "1.0.4" 252 | source_map_stack_trace: 253 | dependency: transitive 254 | description: 255 | name: source_map_stack_trace 256 | sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" 257 | url: "https://pub.dev" 258 | source: hosted 259 | version: "2.1.1" 260 | source_maps: 261 | dependency: transitive 262 | description: 263 | name: source_maps 264 | sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" 265 | url: "https://pub.dev" 266 | source: hosted 267 | version: "0.10.12" 268 | source_span: 269 | dependency: transitive 270 | description: 271 | name: source_span 272 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 273 | url: "https://pub.dev" 274 | source: hosted 275 | version: "1.10.0" 276 | stack_trace: 277 | dependency: transitive 278 | description: 279 | name: stack_trace 280 | sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 281 | url: "https://pub.dev" 282 | source: hosted 283 | version: "1.11.0" 284 | stream_channel: 285 | dependency: transitive 286 | description: 287 | name: stream_channel 288 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 289 | url: "https://pub.dev" 290 | source: hosted 291 | version: "2.1.2" 292 | string_scanner: 293 | dependency: transitive 294 | description: 295 | name: string_scanner 296 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 297 | url: "https://pub.dev" 298 | source: hosted 299 | version: "1.2.0" 300 | term_glyph: 301 | dependency: transitive 302 | description: 303 | name: term_glyph 304 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 305 | url: "https://pub.dev" 306 | source: hosted 307 | version: "1.2.1" 308 | test: 309 | dependency: "direct dev" 310 | description: 311 | name: test 312 | sha256: "67ec5684c7a19b2aba91d2831f3d305a6fd8e1504629c5818f8d64478abf4f38" 313 | url: "https://pub.dev" 314 | source: hosted 315 | version: "1.24.4" 316 | test_api: 317 | dependency: transitive 318 | description: 319 | name: test_api 320 | sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" 321 | url: "https://pub.dev" 322 | source: hosted 323 | version: "0.6.1" 324 | test_core: 325 | dependency: transitive 326 | description: 327 | name: test_core 328 | sha256: "6b753899253c38ca0523bb0eccff3934ec83d011705dae717c61ecf209e333c9" 329 | url: "https://pub.dev" 330 | source: hosted 331 | version: "0.5.4" 332 | typed_data: 333 | dependency: transitive 334 | description: 335 | name: typed_data 336 | sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c 337 | url: "https://pub.dev" 338 | source: hosted 339 | version: "1.3.2" 340 | vm_service: 341 | dependency: transitive 342 | description: 343 | name: vm_service 344 | sha256: b8c67f5fa3897b122cf60fe9ff314f7b0ef71eab25c5f8b771480bc338f48823 345 | url: "https://pub.dev" 346 | source: hosted 347 | version: "11.7.2" 348 | watcher: 349 | dependency: transitive 350 | description: 351 | name: watcher 352 | sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" 353 | url: "https://pub.dev" 354 | source: hosted 355 | version: "1.1.0" 356 | web_socket_channel: 357 | dependency: transitive 358 | description: 359 | name: web_socket_channel 360 | sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b 361 | url: "https://pub.dev" 362 | source: hosted 363 | version: "2.4.0" 364 | webkit_inspection_protocol: 365 | dependency: transitive 366 | description: 367 | name: webkit_inspection_protocol 368 | sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" 369 | url: "https://pub.dev" 370 | source: hosted 371 | version: "1.2.0" 372 | yaml: 373 | dependency: transitive 374 | description: 375 | name: yaml 376 | sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" 377 | url: "https://pub.dev" 378 | source: hosted 379 | version: "3.1.2" 380 | sdks: 381 | dart: ">=3.0.0 <3.7.0" 382 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: result_dart 2 | description: Result for dart. It is an implementation based on Kotlin Result and Swift Result. 3 | version: 2.1.0 4 | repository: https://github.com/Flutterando/result_dart 5 | 6 | environment: 7 | sdk: ">=3.0.0 <4.0.0" 8 | 9 | dependencies: 10 | meta: ^1.3.0 11 | 12 | dev_dependencies: 13 | test: any 14 | flutterando_analysis: ^0.0.2 15 | -------------------------------------------------------------------------------- /test/src/async_result_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:result_dart/functions.dart'; 2 | import 'package:result_dart/result_dart.dart'; 3 | import 'package:test/test.dart'; 4 | 5 | void main() { 6 | group('flatMap', () { 7 | test('async ', () async { 8 | final result = await const Success(1) // 9 | .toAsyncResult() 10 | .flatMap((success) async => Success(success * 2)); 11 | expect(result.getOrNull(), 2); 12 | }); 13 | 14 | test('sink', () async { 15 | final result = await const Success(1) // 16 | .toAsyncResult() 17 | .flatMap((success) => Success(success * 2)); 18 | expect(result.getOrNull(), 2); 19 | }); 20 | }); 21 | 22 | group('flatMapError', () { 23 | test('async ', () async { 24 | final result = await const Failure(1) // 25 | .toAsyncResult() 26 | .flatMapError((error) async => Failure(error * 2)); 27 | expect(result.exceptionOrNull(), 2); 28 | }); 29 | 30 | test('sink', () async { 31 | final result = await const Failure(1) // 32 | .toAsyncResult() 33 | .flatMapError((error) => Failure(error * 2)); 34 | expect(result.exceptionOrNull(), 2); 35 | }); 36 | }); 37 | 38 | test('map', () async { 39 | final result = await const Success(1) // 40 | .toAsyncResult() 41 | .map((success) => success * 2); 42 | 43 | expect(result.getOrNull(), 2); 44 | expect(const Failure(2).toAsyncResult().map(identity), completes); 45 | }); 46 | 47 | test('mapError', () async { 48 | final result = await const Failure(1) // 49 | .toAsyncResult() 50 | .mapError((error) => error * 2); 51 | expect(result.exceptionOrNull(), 2); 52 | expect(const Success(2).toAsyncResult().mapError(identity), completes); 53 | }); 54 | 55 | test('pure', () async { 56 | final result = await const Success(1).toAsyncResult().pure(10); 57 | 58 | expect(result.getOrNull(), 10); 59 | }); 60 | test('pureError', () async { 61 | final result = await const Failure(1).toAsyncResult().pureError(10); 62 | 63 | expect(result.exceptionOrNull(), 10); 64 | }); 65 | 66 | group('swap', () { 67 | test('Success to Error', () async { 68 | final result = const Success(0).toAsyncResult(); 69 | final swap = await result.swap(); 70 | 71 | expect(swap.exceptionOrNull(), 0); 72 | }); 73 | 74 | test('Error to Success', () async { 75 | final result = const Failure(0).toAsyncResult(); 76 | final swap = await result.swap(); 77 | 78 | expect(swap.getOrNull(), 0); 79 | }); 80 | }); 81 | 82 | group('fold', () { 83 | test('Success', () async { 84 | final result = const Success(0).toAsyncResult(); 85 | final futureValue = result.fold(id, (e) => -1); 86 | expect(futureValue, completion(0)); 87 | }); 88 | 89 | test('Error', () async { 90 | final result = const Failure(0).toAsyncResult(); 91 | final futureValue = result.fold(identity, (e) => e); 92 | expect(futureValue, completion(0)); 93 | }); 94 | }); 95 | 96 | group('tryGetSuccess and tryGetError', () { 97 | test('Success', () async { 98 | final result = const Success(0).toAsyncResult(); 99 | 100 | expect(result.isSuccess(), completion(true)); 101 | expect(result.getOrNull(), completion(0)); 102 | }); 103 | 104 | test('Error', () async { 105 | final result = const Failure(0).toAsyncResult(); 106 | 107 | expect(result.isError(), completion(true)); 108 | expect(result.exceptionOrNull(), completion(0)); 109 | }); 110 | }); 111 | 112 | group('getOrThrow', () { 113 | test('Success', () { 114 | final result = const Success(0).toAsyncResult(); 115 | expect(result.getOrThrow(), completion(0)); 116 | }); 117 | 118 | test('Error', () { 119 | final result = const Failure(0).toAsyncResult(); 120 | expect(result.getOrThrow(), throwsA(0)); 121 | }); 122 | }); 123 | 124 | group('getOrElse', () { 125 | test('Success', () { 126 | final result = const Success(0).toAsyncResult(); 127 | final value = result.getOrElse((f) => -1); 128 | expect(value, completion(0)); 129 | }); 130 | 131 | test('Error', () { 132 | final result = const Failure(0).toAsyncResult(); 133 | final value = result.getOrElse((f) => 2); 134 | expect(value, completion(2)); 135 | }); 136 | }); 137 | 138 | group('getOrDefault', () { 139 | test('Success', () { 140 | final result = const Success(0).toAsyncResult(); 141 | final value = result.getOrDefault(-1); 142 | expect(value, completion(0)); 143 | }); 144 | 145 | test('Error', () { 146 | final result = const Failure(0).toAsyncResult(); 147 | final value = result.getOrDefault(2); 148 | expect(value, completion(2)); 149 | }); 150 | }); 151 | 152 | group('recover', () { 153 | test('Success', () { 154 | final result = const Success(0) // 155 | .toAsyncResult() 156 | .recover((f) => const Success(1)); 157 | expect(result.getOrThrow(), completion(0)); 158 | }); 159 | 160 | test('Error', () { 161 | final result = const Failure('failure') // 162 | .toAsyncResult() 163 | .recover((f) => const Success(1)); 164 | expect(result.getOrThrow(), completion(1)); 165 | }); 166 | }); 167 | 168 | group('onSuccess', () { 169 | test('Success', () { 170 | const Success(0) // 171 | .toAsyncResult() 172 | .onFailure((failure) {}) 173 | .onSuccess( 174 | expectAsync1( 175 | (value) { 176 | expect(value, 0); 177 | }, 178 | ), 179 | ); 180 | }); 181 | 182 | test('Error', () { 183 | const Failure('failure') // 184 | .toAsyncResult() 185 | .onSuccess((success) {}) 186 | .onFailure( 187 | expectAsync1( 188 | (value) { 189 | expect(value, 'failure'); 190 | }, 191 | ), 192 | ); 193 | }); 194 | }); 195 | } 196 | -------------------------------------------------------------------------------- /test/src/result_dart_base_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:result_dart/result_dart.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | void main() { 5 | test('result dart base ...', () { 6 | final result = const Success(0).pureFold(1, 's'); 7 | 8 | expect(result, isA>()); 9 | expect(result.getOrThrow(), 1); 10 | }); 11 | } 12 | -------------------------------------------------------------------------------- /test/src/result_extension_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:result_dart/src/result_dart_base.dart'; 2 | import 'package:result_dart/src/result_extension.dart'; 3 | import 'package:test/test.dart'; 4 | 5 | void main() { 6 | group('toError', () { 7 | test('without result type', () { 8 | final result = 'error'.toFailure(); 9 | 10 | expect(result, isA>()); 11 | expect(result.exceptionOrNull(), isA()); 12 | expect(result.exceptionOrNull(), 'error'); 13 | }); 14 | 15 | test('with result type', () { 16 | final ResultDart result = 'error'.toFailure(); 17 | 18 | expect(result, isA>()); 19 | expect(result.exceptionOrNull(), isA()); 20 | expect(result.exceptionOrNull(), 'error'); 21 | }); 22 | 23 | test('throw AssertException if is a Result object', () { 24 | final ResultDart result = 'error'.toFailure(); 25 | expect(result.toFailure, throwsA(isA())); 26 | }); 27 | 28 | test('throw AssertException if is a Future object', () { 29 | expect(Future.value().toFailure, throwsA(isA())); 30 | }); 31 | }); 32 | 33 | group('toSuccess', () { 34 | test('without result type', () { 35 | final result = 'success'.toSuccess(); 36 | 37 | expect(result, isA>()); 38 | expect(result.getOrNull(), 'success'); 39 | }); 40 | 41 | test('with result type', () { 42 | final ResultDart result = 'success'.toSuccess(); 43 | 44 | expect(result, isA>()); 45 | expect(result.getOrNull(), 'success'); 46 | }); 47 | 48 | test('throw AssertException if is a Result object', () { 49 | final result = 'success'.toSuccess(); 50 | expect(result.toSuccess, throwsA(isA())); 51 | }); 52 | 53 | test('throw AssertException if is a Future object', () { 54 | expect(Future.value().toSuccess, throwsA(isA())); 55 | }); 56 | }); 57 | } 58 | -------------------------------------------------------------------------------- /test/src/result_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:meta/meta.dart'; 2 | import 'package:result_dart/functions.dart'; 3 | import 'package:result_dart/result_dart.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | late MyUseCase useCase; 8 | 9 | setUpAll(() { 10 | useCase = MyUseCase(); 11 | }); 12 | 13 | group('factories', () { 14 | test('Success.unit', () { 15 | final result = Success.unit(); 16 | expect(result.getOrNull(), unit); 17 | }); 18 | 19 | test('Success.unit type infer', () { 20 | ResultDart fn() { 21 | return Success.unit(); 22 | } 23 | 24 | final result = fn(); 25 | expect(result.getOrNull(), unit); 26 | }); 27 | 28 | test('Error.unit', () { 29 | final result = Failure.unit(); 30 | expect(result.exceptionOrNull(), unit); 31 | }); 32 | 33 | test('Error.unit type infer', () { 34 | ResultDart fn() { 35 | return Failure.unit(); 36 | } 37 | 38 | final result = fn(); 39 | expect(result.exceptionOrNull(), unit); 40 | }); 41 | }); 42 | 43 | test(''' 44 | Given a success result, 45 | When getting the result through tryGetSuccess, 46 | should return the success value''', () { 47 | final result = useCase(); 48 | 49 | MyResult? successResult; 50 | if (result.isSuccess()) { 51 | successResult = result.getOrNull(); 52 | } 53 | 54 | expect(successResult!.value, isA()); 55 | expect(result.isError(), isFalse); 56 | }); 57 | 58 | test(''' 59 | Given an error result, 60 | When getting the result through tryGetSuccess, 61 | should return null ''', () { 62 | final result = useCase(returnError: true); 63 | 64 | MyResult? successResult; 65 | if (result.isSuccess()) { 66 | successResult = result.getOrNull(); 67 | } 68 | 69 | expect(successResult?.value, null); 70 | }); 71 | 72 | test(''' 73 | Given an error result, 74 | When getting the result through the tryGetError, 75 | should return the error value 76 | ''', () { 77 | final result = useCase(returnError: true); 78 | 79 | MyException? exceptionResult; 80 | if (result.isError()) { 81 | exceptionResult = result.exceptionOrNull(); 82 | } 83 | 84 | expect(exceptionResult != null, true); 85 | expect(result.isSuccess(), isFalse); 86 | }); 87 | 88 | test('equatable', () { 89 | expect(const Success(1) == const Success(1), isTrue); 90 | expect(const Success(1).hashCode == const Success(1).hashCode, isTrue); 91 | 92 | expect(const Failure(1) == const Failure(1), isTrue); 93 | expect(const Failure(1).hashCode == const Failure(1).hashCode, isTrue); 94 | }); 95 | 96 | group('Map', () { 97 | test('Success', () { 98 | final result = successOf(4); 99 | final result2 = result.map((success) => '=' * success); 100 | 101 | expect(result2.getOrNull(), '===='); 102 | }); 103 | 104 | test('Error', () { 105 | final result = failureOf(4); 106 | final result2 = result.map((success) => 'change'); 107 | 108 | expect(result2.getOrNull(), isNull); 109 | expect(result2.exceptionOrNull(), 4); 110 | }); 111 | }); 112 | 113 | group('MapError', () { 114 | test('Success', () { 115 | const result = Success(4); 116 | final result2 = result.mapError((error) => '=' * error); 117 | 118 | expect(result2.getOrNull(), 4); 119 | expect(result2.exceptionOrNull(), isNull); 120 | }); 121 | 122 | test('Error', () { 123 | const result = Failure(4); 124 | final result2 = result.mapError((error) => 'change'); 125 | 126 | expect(result2.getOrNull(), isNull); 127 | expect(result2.exceptionOrNull(), 'change'); 128 | }); 129 | }); 130 | 131 | group('flatMap', () { 132 | test('Success', () { 133 | const result = Success(4); 134 | final result2 = result.flatMap((success) => Success('=' * success)); 135 | 136 | expect(result2.getOrNull(), '===='); 137 | }); 138 | 139 | test('Error', () { 140 | const result = Failure(4); 141 | final result2 = result.flatMap(Success.new); 142 | 143 | expect(result2.getOrNull(), isNull); 144 | expect(result2.exceptionOrNull(), 4); 145 | }); 146 | }); 147 | 148 | group('flatMapError', () { 149 | test('Error', () { 150 | const result = Failure(4); 151 | final result2 = result.flatMapError((error) => Failure('=' * error)); 152 | 153 | expect(result2.exceptionOrNull(), '===='); 154 | }); 155 | 156 | test('Success', () { 157 | const result = Success(4); 158 | final result2 = result.flatMapError(Failure.new); 159 | 160 | expect(result2.getOrNull(), 4); 161 | expect(result2.exceptionOrNull(), isNull); 162 | }); 163 | }); 164 | 165 | group('pure', () { 166 | test('Success', () { 167 | final result = const Success(4) // 168 | .pure(6) 169 | .map((success) => '=' * success); 170 | 171 | expect(result.getOrNull(), '======'); 172 | }); 173 | 174 | test('Error', () { 175 | final result = const Failure(4).pure(6); 176 | 177 | expect(result.getOrNull(), isNull); 178 | expect(result.exceptionOrNull(), 4); 179 | }); 180 | }); 181 | 182 | group('pureError', () { 183 | test('Error', () { 184 | final result = const Failure(4) // 185 | .pureError(6) 186 | .mapError((error) => '=' * error); 187 | 188 | expect(result.exceptionOrNull(), '======'); 189 | }); 190 | 191 | test('Success', () { 192 | final result = const Success(4).pureError(6); 193 | 194 | expect(result.exceptionOrNull(), isNull); 195 | expect(result.getOrNull(), 4); 196 | }); 197 | }); 198 | 199 | test('toAsyncResult', () { 200 | const result = Success(0); 201 | 202 | expect(result.toAsyncResult(), isA>>()); 203 | }); 204 | 205 | group('swap', () { 206 | test('Success to Error', () { 207 | const result = Success(0); 208 | final swap = result.swap(); 209 | 210 | expect(swap.exceptionOrNull(), 0); 211 | }); 212 | 213 | test('Error to Success', () { 214 | const result = Failure(0); 215 | final swap = result.swap(); 216 | 217 | expect(swap.getOrNull(), 0); 218 | }); 219 | }); 220 | 221 | group('fold', () { 222 | test('Success', () { 223 | const result = Success(0); 224 | final futureValue = result.fold(id, (e) => -1); 225 | expect(futureValue, 0); 226 | }); 227 | 228 | test('Error', () { 229 | const result = Failure(0); 230 | final futureValue = result.fold((success) => -1, identity); 231 | expect(futureValue, 0); 232 | }); 233 | }); 234 | 235 | group('getOrThrow', () { 236 | test('Success', () { 237 | const result = Success(0); 238 | expect(result.getOrThrow(), 0); 239 | }); 240 | 241 | test('Error', () { 242 | const result = Failure(0); 243 | expect(result.getOrThrow, throwsA(0)); 244 | }); 245 | }); 246 | 247 | group('getOrElse', () { 248 | test('Success', () { 249 | const result = Success(0); 250 | final value = result.getOrElse((f) => -1); 251 | expect(value, 0); 252 | }); 253 | 254 | test('Error', () { 255 | const result = Failure(0); 256 | final value = result.getOrElse((f) => 2); 257 | expect(value, 2); 258 | }); 259 | }); 260 | 261 | group('getOrDefault', () { 262 | test('Success', () { 263 | const result = Success(0); 264 | final value = result.getOrDefault(-1); 265 | expect(value, 0); 266 | }); 267 | 268 | test('Error', () { 269 | const result = Failure(0); 270 | final value = result.getOrDefault(2); 271 | expect(value, 2); 272 | }); 273 | }); 274 | 275 | group('recover', () { 276 | test('Success', () { 277 | final result = const Success(0) // 278 | .recover((f) => const Success(1)); 279 | expect(result.getOrThrow(), 0); 280 | }); 281 | 282 | test('Error', () { 283 | final result = const Failure('failure') // 284 | .recover((f) => const Success(1)); 285 | expect(result.getOrThrow(), 1); 286 | }); 287 | }); 288 | } 289 | 290 | ResultDart getMockedSuccessResult() { 291 | return Success.unit(); 292 | } 293 | 294 | class MyUseCase { 295 | ResultDart call({bool returnError = false}) { 296 | if (returnError) { 297 | return const Failure(MyException('something went wrong')); 298 | } else { 299 | return const Success(MyResult('nice')); 300 | } 301 | } 302 | } 303 | 304 | @immutable 305 | class MyException implements Exception { 306 | final String message; 307 | 308 | const MyException(this.message); 309 | 310 | @override 311 | int get hashCode => message.hashCode; 312 | 313 | @override 314 | bool operator ==(Object other) => // 315 | other is MyException && other.message == message; 316 | } 317 | 318 | @immutable 319 | class MyResult { 320 | const MyResult(this.value); 321 | 322 | final String value; 323 | 324 | @override 325 | int get hashCode => value.hashCode; 326 | 327 | @override 328 | bool operator ==(Object other) => other is MyResult && other.value == value; 329 | } 330 | --------------------------------------------------------------------------------