├── .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 | [](https://pub.dev/packages/result_dart)
32 | [](https://pub.dev/packages/result_dart/score)
33 | [](https://pub.dev/packages/flutterando_analysis/)
34 |
35 | [](https://pub.dev/publishers/flutterando.com.br/packages)
36 |
37 |
38 |
39 |
40 |
41 |
42 | ---
43 |
44 |
45 |
46 | Table of Contents
47 |
48 | - About The Project
49 | m - Getting Started
50 | - How to Use
51 | - Features
52 | - Contributing
53 | - Contact
54 | - Acknowledgements
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 |
--------------------------------------------------------------------------------