diff --git a/app/lib/int_extension.dart b/app/lib/int_extension.dart new file mode 100644 index 00000000..c666cccf --- /dev/null +++ b/app/lib/int_extension.dart @@ -0,0 +1,15 @@ +extension IntExtension on int { + Iterable until(int to, [int step = 1]) sync* { + if (step == 0) { + throw ArgumentError("step must not be zero"); + } + final sign = (to - this).sign; + if (sign != step.sign) { + // e.g., 0.until(10, -1) or 0.until(-10, 1) + return; + } + for (var i = this; sign > 0 ? i < to : i > to; i += step) { + yield i; + } + } +} diff --git a/app/test/int_extension_test.dart b/app/test/int_extension_test.dart new file mode 100644 index 00000000..de01689e --- /dev/null +++ b/app/test/int_extension_test.dart @@ -0,0 +1,48 @@ +import 'package:nc_photos/int_extension.dart'; +import 'package:test/test.dart'; + +void main() { + group("IntExtension", () { + group("until", () { + /// Expected: exception + test("step == 0", () { + expect(() => 1.until(10, 0), throwsArgumentError); + }); + + /// Expected: [1, ..., 9] + test("+to > +beg, default step", () { + expect(1.until(10).toList(), List.generate(9, (i) => i + 1)); + }); + + /// Expected: [1, 3, ..., 9] + test("+to > +beg, step = 2", () { + expect(1.until(10, 2).toList(), List.generate(5, (i) => i + 1 + i)); + }); + + /// Expected: [] + test("+to > +beg, -step", () { + expect(1.until(10, -1).toList(), []); + }); + + /// Expected: [] + test("+to < +beg, +step", () { + expect(10.until(1).toList(), []); + }); + + /// Expected: [10, ..., 2] + test("+to < +beg, -step", () { + expect(10.until(1, -1).toList(), List.generate(9, (i) => 10 - i)); + }); + + /// Expected: [-10, ..., -2] + test("-to > -beg, +step", () { + expect((-10).until(-1, 1).toList(), List.generate(9, (i) => i + -10)); + }); + + /// Expected: [-1, ..., -9] + test("-to < -beg, -step", () { + expect((-1).until(-10, -1).toList(), List.generate(9, (i) => -1 - i)); + }); + }); + }); +}