test: dates with precision
test: selectInJson refactor: remove unused selectMultipleInJson and date relative date formattingmain
parent
0a9a8d033f
commit
57708bc894
|
@ -12,15 +12,6 @@ Iterable<T> selectInJson<T>(dynamic json, String path) {
|
||||||
return selectInJsonWithPath<T>(json, path).map((e) => e.value);
|
return selectInJsonWithPath<T>(json, path).map((e) => e.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Iterable<dynamic>> selectMultipleInJson(
|
|
||||||
dynamic json, Map<String, String> selector) {
|
|
||||||
Map<String, Iterable<dynamic>> result = {};
|
|
||||||
for (String key in selector.keys) {
|
|
||||||
result[key] = selectInJsonWithPath(json, selector[key]!);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Select values in nested [List] and [Map] structures using a path that may contain wildcards.
|
/// Select values in nested [List] and [Map] structures using a path that may contain wildcards.
|
||||||
///
|
///
|
||||||
/// The maps must always use [String] keys.
|
/// The maps must always use [String] keys.
|
||||||
|
@ -40,13 +31,18 @@ Iterable<({T value, String path})> selectInJsonWithPath<T>(
|
||||||
List<String> pathParts = path.split(".");
|
List<String> pathParts = path.split(".");
|
||||||
String first = pathParts.removeAt(0);
|
String first = pathParts.removeAt(0);
|
||||||
String rest = pathParts.join(".");
|
String rest = pathParts.join(".");
|
||||||
addFirstToPath(({T value, String path}) element) => (
|
({T value, String path}) addFirstToPath(({T value, String path}) element) {
|
||||||
value: element.value,
|
return (
|
||||||
path: element.path.isEmpty ? first : "$first.${element.path}"
|
value: element.value,
|
||||||
);
|
path: element.path.isEmpty ? first : "$first.${element.path}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (first == "*" || first == "**") {
|
if (first == "*" || first == "**") {
|
||||||
String continueWithPath = first == "*" ? rest : path;
|
String continueWithPath = first == "*" ? rest : path;
|
||||||
|
if (first == "**") {
|
||||||
|
yield* selectInJsonWithPath<T>(json, rest);
|
||||||
|
}
|
||||||
if (json is List) {
|
if (json is List) {
|
||||||
yield* json
|
yield* json
|
||||||
.expand((e) => selectInJsonWithPath<T>(e, continueWithPath))
|
.expand((e) => selectInJsonWithPath<T>(e, continueWithPath))
|
||||||
|
|
|
@ -6,6 +6,4 @@ class MovieApi {
|
||||||
[];
|
[];
|
||||||
|
|
||||||
Future<List<MovieData>> searchForMovies(String searchTerm) async => [];
|
Future<List<MovieData>> searchForMovies(String searchTerm) async => [];
|
||||||
|
|
||||||
Future<void> addMovieDetails(List<MovieData> movies) async {}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,12 +41,6 @@ class WikidataMovieApi implements MovieApi {
|
||||||
ApiManager queryApi =
|
ApiManager queryApi =
|
||||||
ApiManager("https://query.wikidata.org/sparql?format=json&origin=*");
|
ApiManager("https://query.wikidata.org/sparql?format=json&origin=*");
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> addMovieDetails(List<MovieData> movies) {
|
|
||||||
// TODO: implement addMovieDetails
|
|
||||||
throw UnimplementedError();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<WikidataMovieData>> getUpcomingMovies(DateTime startDate,
|
Future<List<WikidataMovieData>> getUpcomingMovies(DateTime startDate,
|
||||||
[int count = 100]) async {
|
[int count = 100]) async {
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
/// Compares dates relative to each other. Times are ignored.
|
|
||||||
String dateRelativeToNow(DateTime date) {
|
|
||||||
DateTime dateOnly = DateTime.utc(date.year, date.month, date.day);
|
|
||||||
DateTime now = DateTime.now().toUtc();
|
|
||||||
DateTime today = DateTime.utc(now.year, now.month, now.day);
|
|
||||||
Duration diff = dateOnly.difference(today);
|
|
||||||
return _durationToRelativeDateString(diff);
|
|
||||||
}
|
|
||||||
|
|
||||||
String _durationToRelativeDateString(Duration duration) {
|
|
||||||
if (duration == const Duration(days: 1)) {
|
|
||||||
return "Tomorrow";
|
|
||||||
} else if (duration == const Duration(days: -1)) {
|
|
||||||
return "Yesterday";
|
|
||||||
}
|
|
||||||
if (duration.isNegative) {
|
|
||||||
String result = _durationApproximatedInWords(-duration);
|
|
||||||
return "${result[0].toUpperCase()}${result.substring(1)} ago";
|
|
||||||
} else if (duration == Duration.zero) {
|
|
||||||
return "Today";
|
|
||||||
} else {
|
|
||||||
return "In ${_durationApproximatedInWords(duration)}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String _durationApproximatedInWords(Duration duration) {
|
|
||||||
int days = duration.inDays;
|
|
||||||
int weeks = (days / 7).floor();
|
|
||||||
int months = (days / 30).floor();
|
|
||||||
int years = (days / 365).floor();
|
|
||||||
int centuries = (years / 100).floor();
|
|
||||||
if (duration == Duration.zero) {
|
|
||||||
return "now";
|
|
||||||
}
|
|
||||||
if (days < 7) {
|
|
||||||
return days > 1 ? "$days days" : "a day";
|
|
||||||
}
|
|
||||||
if (months == 0) {
|
|
||||||
return weeks > 1 ? "$weeks weeks" : "a week";
|
|
||||||
}
|
|
||||||
if (years == 0) {
|
|
||||||
return months > 1 ? "$months months" : "a month";
|
|
||||||
}
|
|
||||||
if (years < 100) {
|
|
||||||
return years > 1 ? "$years years" : "a year";
|
|
||||||
}
|
|
||||||
return centuries > 1 ? "$centuries centuries" : "a century";
|
|
||||||
}
|
|
|
@ -1,18 +1,25 @@
|
||||||
import 'package:get_storage/get_storage.dart';
|
import 'package:get_storage/get_storage.dart';
|
||||||
import 'package:release_schedule/model/movie.dart';
|
import 'package:release_schedule/model/movie.dart';
|
||||||
|
|
||||||
class LocalMovieStorage {
|
abstract class LocalMovieStorage {
|
||||||
|
void update(List<MovieData> movies);
|
||||||
|
Future<List<MovieData>> retrieve();
|
||||||
|
}
|
||||||
|
|
||||||
|
class InMemoryMovieStorage implements LocalMovieStorage {
|
||||||
List<MovieData> _storedMovies = [];
|
List<MovieData> _storedMovies = [];
|
||||||
|
@override
|
||||||
update(List<MovieData> movies) {
|
update(List<MovieData> movies) {
|
||||||
_storedMovies = movies;
|
_storedMovies = movies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<MovieData>> retrieve() async {
|
Future<List<MovieData>> retrieve() async {
|
||||||
return _storedMovies;
|
return _storedMovies;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LocalMovieStorageGetStorage extends LocalMovieStorage {
|
class LocalMovieStorageGetStorage implements LocalMovieStorage {
|
||||||
Future<void>? initialized;
|
Future<void>? initialized;
|
||||||
GetStorage? container;
|
GetStorage? container;
|
||||||
MovieData Function(Map jsonEncodable) toMovieData;
|
MovieData Function(Map jsonEncodable) toMovieData;
|
||||||
|
|
|
@ -10,7 +10,6 @@ class MovieData extends ChangeNotifier {
|
||||||
List<DateWithPrecisionAndCountry>? _releaseDates;
|
List<DateWithPrecisionAndCountry>? _releaseDates;
|
||||||
List<String>? _genres;
|
List<String>? _genres;
|
||||||
List<TitleInLanguage>? _titles;
|
List<TitleInLanguage>? _titles;
|
||||||
List<Review>? _reviews;
|
|
||||||
|
|
||||||
MovieData(this._title, this._releaseDate);
|
MovieData(this._title, this._releaseDate);
|
||||||
|
|
||||||
|
@ -38,10 +37,6 @@ class MovieData extends ChangeNotifier {
|
||||||
return _titles;
|
return _titles;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Review>? get reviews {
|
|
||||||
return _reviews;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get hasDetails {
|
bool get hasDetails {
|
||||||
return _hasDetails;
|
return _hasDetails;
|
||||||
}
|
}
|
||||||
|
@ -54,8 +49,7 @@ class MovieData extends ChangeNotifier {
|
||||||
releaseDate: movie.releaseDate,
|
releaseDate: movie.releaseDate,
|
||||||
releaseDates: movie.releaseDates,
|
releaseDates: movie.releaseDates,
|
||||||
genres: movie.genres,
|
genres: movie.genres,
|
||||||
titles: movie.titles,
|
titles: movie.titles);
|
||||||
reviews: movie.reviews);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDetails(
|
void setDetails(
|
||||||
|
@ -64,8 +58,7 @@ class MovieData extends ChangeNotifier {
|
||||||
bool? bookmarked,
|
bool? bookmarked,
|
||||||
List<DateWithPrecisionAndCountry>? releaseDates,
|
List<DateWithPrecisionAndCountry>? releaseDates,
|
||||||
List<String>? genres,
|
List<String>? genres,
|
||||||
List<TitleInLanguage>? titles,
|
List<TitleInLanguage>? titles}) {
|
||||||
List<Review>? reviews}) {
|
|
||||||
if (title != null) {
|
if (title != null) {
|
||||||
_title = title;
|
_title = title;
|
||||||
}
|
}
|
||||||
|
@ -84,16 +77,13 @@ class MovieData extends ChangeNotifier {
|
||||||
if (titles != null) {
|
if (titles != null) {
|
||||||
_titles = titles;
|
_titles = titles;
|
||||||
}
|
}
|
||||||
if (reviews != null) {
|
|
||||||
_reviews = reviews;
|
|
||||||
}
|
|
||||||
_hasDetails = true;
|
_hasDetails = true;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return "$title (${_releaseDate.toString()}${_genres?.isNotEmpty ?? true ? "; ${_genres?.join(", ")}" : ""})";
|
return "$title (${_releaseDate.toString()}${_genres?.isNotEmpty ?? false ? "; ${_genres?.join(", ")}" : ""})";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool same(MovieData other) {
|
bool same(MovieData other) {
|
||||||
|
@ -112,7 +102,6 @@ class MovieData extends ChangeNotifier {
|
||||||
"releaseDates": releaseDatesByCountry,
|
"releaseDates": releaseDatesByCountry,
|
||||||
"genres": genres,
|
"genres": genres,
|
||||||
"titles": titlesByCountry,
|
"titles": titlesByCountry,
|
||||||
"reviews": reviews?.map((review) => review.toJsonEncodable()).toList(),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,11 +120,6 @@ class MovieData extends ChangeNotifier {
|
||||||
DateWithPrecisionAndCountry.fromJsonEncodable(release))
|
DateWithPrecisionAndCountry.fromJsonEncodable(release))
|
||||||
.toList()
|
.toList()
|
||||||
: null,
|
: null,
|
||||||
reviews: json["reviews"] != null
|
|
||||||
? (json["reviews"] as List<dynamic>)
|
|
||||||
.map((review) => Review.fromJsonEncodable(review))
|
|
||||||
.toList()
|
|
||||||
: null,
|
|
||||||
titles: json["titles"] != null
|
titles: json["titles"] != null
|
||||||
? (json["titles"] as List<dynamic>)
|
? (json["titles"] as List<dynamic>)
|
||||||
.map((title) =>
|
.map((title) =>
|
||||||
|
@ -168,26 +152,3 @@ class DateWithPrecisionAndCountry {
|
||||||
return "${dateWithPrecision.toString()} ($country)";
|
return "${dateWithPrecision.toString()} ($country)";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Review {
|
|
||||||
String score;
|
|
||||||
String by;
|
|
||||||
DateTime asOf;
|
|
||||||
int count;
|
|
||||||
|
|
||||||
Review(this.score, this.by, this.asOf, this.count);
|
|
||||||
Review.fromJsonEncodable(Map json)
|
|
||||||
: score = json["score"],
|
|
||||||
by = json["by"],
|
|
||||||
asOf = DateTime.parse(json["asOf"]),
|
|
||||||
count = json["count"];
|
|
||||||
|
|
||||||
Map toJsonEncodable() {
|
|
||||||
return {
|
|
||||||
"score": score,
|
|
||||||
"by": by,
|
|
||||||
"asOf": asOf.toIso8601String(),
|
|
||||||
"count": count,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ class MovieManager extends ChangeNotifier {
|
||||||
bool added = false;
|
bool added = false;
|
||||||
for (var movie in additionalMovies) {
|
for (var movie in additionalMovies) {
|
||||||
MovieData? existing =
|
MovieData? existing =
|
||||||
firstWhereOrNull(movies, (element) => movie.same(element));
|
movies.where((element) => movie.same(element)).firstOrNull;
|
||||||
if (existing == null) {
|
if (existing == null) {
|
||||||
_insertMovie(movie);
|
_insertMovie(movie);
|
||||||
movie.addListener(() {
|
movie.addListener(() {
|
||||||
|
@ -131,10 +131,6 @@ class MovieManager extends ChangeNotifier {
|
||||||
return addMovies(movies);
|
return addMovies(movies);
|
||||||
}
|
}
|
||||||
|
|
||||||
void expandDetails(List<MovieData> movies) {
|
|
||||||
api.addMovieDetails(movies);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> loadUpcomingMovies() async {
|
Future<void> loadUpcomingMovies() async {
|
||||||
try {
|
try {
|
||||||
loading = true;
|
loading = true;
|
||||||
|
@ -148,11 +144,3 @@ class MovieManager extends ChangeNotifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
T? firstWhereOrNull<T>(List<T> list, bool Function(T element) test) {
|
|
||||||
try {
|
|
||||||
return list.firstWhere(test);
|
|
||||||
} catch (e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,6 +4,9 @@ class Scored<T> {
|
||||||
T data;
|
T data;
|
||||||
double score;
|
double score;
|
||||||
Scored(this.data, this.score);
|
Scored(this.data, this.score);
|
||||||
|
|
||||||
|
@override
|
||||||
|
toString() => '$data: $score';
|
||||||
}
|
}
|
||||||
|
|
||||||
List<T> searchList<T>(
|
List<T> searchList<T>(
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:release_schedule/model/date_format.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
group('dateRelativeToNow', () {
|
|
||||||
test('returns "Today" for today\'s date', () {
|
|
||||||
final today = DateTime.now();
|
|
||||||
final result = dateRelativeToNow(today);
|
|
||||||
expect(result, 'Today');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('returns "Tomorrow" for tomorrow\'s date', () {
|
|
||||||
final tomorrow = DateTime.now().add(const Duration(days: 1));
|
|
||||||
final result = dateRelativeToNow(tomorrow);
|
|
||||||
expect(result, 'Tomorrow');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('returns "Yesterday" for yesterday\'s date', () {
|
|
||||||
final yesterday = DateTime.now().subtract(const Duration(days: 1));
|
|
||||||
final result = dateRelativeToNow(yesterday);
|
|
||||||
expect(result, 'Yesterday');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('returns "In 5 days" for a date 5 days in the future', () {
|
|
||||||
final futureDate = DateTime.now().add(const Duration(days: 5));
|
|
||||||
final result = dateRelativeToNow(futureDate);
|
|
||||||
expect(result, 'In 5 days');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('returns "5 days ago" for a date 5 days in the past', () {
|
|
||||||
final pastDate = DateTime.now().subtract(const Duration(days: 5));
|
|
||||||
final result = dateRelativeToNow(pastDate);
|
|
||||||
expect(result, '5 days ago');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('returns "a week" for a date 7 days in the future', () {
|
|
||||||
final futureDate = DateTime.now().add(const Duration(days: 7));
|
|
||||||
final result = dateRelativeToNow(futureDate);
|
|
||||||
expect(result, 'In a week');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('returns "a week" for a date 7 days in the past', () {
|
|
||||||
final pastDate = DateTime.now().subtract(const Duration(days: 7));
|
|
||||||
final result = dateRelativeToNow(pastDate);
|
|
||||||
expect(result, 'A week ago');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('returns "a month" for a date 30 days in the future', () {
|
|
||||||
final futureDate = DateTime.now().add(const Duration(days: 30));
|
|
||||||
final result = dateRelativeToNow(futureDate);
|
|
||||||
expect(result, 'In a month');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('returns "a month" for a date 30 days in the past', () {
|
|
||||||
final pastDate = DateTime.now().subtract(const Duration(days: 30));
|
|
||||||
final result = dateRelativeToNow(pastDate);
|
|
||||||
expect(result, 'A month ago');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('returns "a year" for a date 365 days in the future', () {
|
|
||||||
final futureDate = DateTime.now().add(const Duration(days: 365));
|
|
||||||
final result = dateRelativeToNow(futureDate);
|
|
||||||
expect(result, 'In a year');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('returns "a year" for a date 365 days in the past', () {
|
|
||||||
final pastDate = DateTime.now().subtract(const Duration(days: 365));
|
|
||||||
final result = dateRelativeToNow(pastDate);
|
|
||||||
expect(result, 'A year ago');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('returns "a century" for a date 100 years in the future', () {
|
|
||||||
final futureDate = DateTime.now().add(const Duration(days: 365 * 100));
|
|
||||||
final result = dateRelativeToNow(futureDate);
|
|
||||||
expect(result, 'In a century');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('returns "a century" for a date 100 years in the past', () {
|
|
||||||
final pastDate = DateTime.now().subtract(const Duration(days: 365 * 100));
|
|
||||||
final result = dateRelativeToNow(pastDate);
|
|
||||||
expect(result, 'A century ago');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:release_schedule/model/dates.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group("DatePrecisionComparison", () {
|
||||||
|
test("can compare with inequality", () {
|
||||||
|
expect(DatePrecision.decade < DatePrecision.year, isTrue);
|
||||||
|
expect(DatePrecision.year <= DatePrecision.year, isTrue);
|
||||||
|
expect(DatePrecision.month > DatePrecision.day, isFalse);
|
||||||
|
expect(DatePrecision.day > DatePrecision.day, isFalse);
|
||||||
|
expect(DatePrecision.hour >= DatePrecision.month, isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("can compare with equality", () {
|
||||||
|
expect(DatePrecision.decade == DatePrecision.decade, isTrue);
|
||||||
|
expect(DatePrecision.year != DatePrecision.decade, isTrue);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("simplifyDatesToPrecision", () {
|
||||||
|
expect(simplifyDateToPrecision(DateTime(2024, 5, 14), DatePrecision.decade),
|
||||||
|
equals(DateTime(2020, 1, 1)));
|
||||||
|
expect(simplifyDateToPrecision(DateTime(2024, 5, 14), DatePrecision.year),
|
||||||
|
equals(DateTime(2024, 1, 1)));
|
||||||
|
expect(simplifyDateToPrecision(DateTime(2024, 5, 14), DatePrecision.month),
|
||||||
|
equals(DateTime(2024, 5, 1)));
|
||||||
|
expect(
|
||||||
|
simplifyDateToPrecision(
|
||||||
|
DateTime(2024, 5, 14, 10, 42), DatePrecision.day),
|
||||||
|
equals(DateTime(2024, 5, 14)));
|
||||||
|
expect(
|
||||||
|
simplifyDateToPrecision(
|
||||||
|
DateTime(2024, 5, 14, 10, 42), DatePrecision.hour),
|
||||||
|
equals(DateTime(2024, 5, 14, 10)));
|
||||||
|
expect(
|
||||||
|
simplifyDateToPrecision(
|
||||||
|
DateTime(2024, 5, 14, 10, 42, 12), DatePrecision.minute),
|
||||||
|
equals(DateTime(2024, 5, 14, 10, 42)));
|
||||||
|
});
|
||||||
|
|
||||||
|
group("DateWithPrecision", () {
|
||||||
|
test("includes", () {
|
||||||
|
DateTime originalDate = DateTime(2024, 5, 14, 15, 42, 12);
|
||||||
|
expect(
|
||||||
|
DateWithPrecision(originalDate, DatePrecision.minute)
|
||||||
|
.includes(DateTime(2024, 5, 14, 15, 42, 12)),
|
||||||
|
isTrue);
|
||||||
|
expect(
|
||||||
|
DateWithPrecision(originalDate, DatePrecision.minute)
|
||||||
|
.includes(DateTime(2024, 5, 14, 15, 43, 1)),
|
||||||
|
isFalse);
|
||||||
|
expect(
|
||||||
|
DateWithPrecision(originalDate, DatePrecision.hour)
|
||||||
|
.includes(DateTime(2024, 5, 14, 15, 42, 12)),
|
||||||
|
isTrue);
|
||||||
|
expect(
|
||||||
|
DateWithPrecision(originalDate, DatePrecision.hour)
|
||||||
|
.includes(DateTime(2024, 5, 14, 16, 10, 12)),
|
||||||
|
isFalse);
|
||||||
|
expect(
|
||||||
|
DateWithPrecision(originalDate, DatePrecision.day)
|
||||||
|
.includes(DateTime(2024, 5, 14)),
|
||||||
|
isTrue);
|
||||||
|
expect(
|
||||||
|
DateWithPrecision(originalDate, DatePrecision.day)
|
||||||
|
.includes(DateTime(2024, 5, 15)),
|
||||||
|
isFalse);
|
||||||
|
expect(
|
||||||
|
DateWithPrecision(originalDate, DatePrecision.month)
|
||||||
|
.includes(DateTime(2024, 5, 20)),
|
||||||
|
isTrue);
|
||||||
|
expect(
|
||||||
|
DateWithPrecision(originalDate, DatePrecision.month)
|
||||||
|
.includes(DateTime(2024, 6, 10)),
|
||||||
|
isFalse);
|
||||||
|
expect(
|
||||||
|
DateWithPrecision(originalDate, DatePrecision.year)
|
||||||
|
.includes(DateTime(2024, 12, 31)),
|
||||||
|
isTrue);
|
||||||
|
expect(
|
||||||
|
DateWithPrecision(originalDate, DatePrecision.year)
|
||||||
|
.includes(DateTime(2025, 1, 1)),
|
||||||
|
isFalse);
|
||||||
|
expect(
|
||||||
|
DateWithPrecision(originalDate, DatePrecision.decade)
|
||||||
|
.includes(DateTime(2029, 12, 31)),
|
||||||
|
isTrue);
|
||||||
|
expect(
|
||||||
|
DateWithPrecision(originalDate, DatePrecision.decade)
|
||||||
|
.includes(DateTime(2020, 1, 1)),
|
||||||
|
isTrue);
|
||||||
|
expect(
|
||||||
|
DateWithPrecision(originalDate, DatePrecision.decade)
|
||||||
|
.includes(DateTime(2030, 1, 1)),
|
||||||
|
isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("toString", () {
|
||||||
|
DateTime date = DateTime(2024, 5, 14, 15, 42, 12);
|
||||||
|
expect(DateWithPrecision(date, DatePrecision.minute).toString(),
|
||||||
|
equals("May 14, 2024, 15:42"));
|
||||||
|
expect(DateWithPrecision(date, DatePrecision.hour).toString(),
|
||||||
|
equals("May 14, 2024, 15"));
|
||||||
|
expect(DateWithPrecision(date, DatePrecision.day).toString(),
|
||||||
|
equals("May 14, 2024"));
|
||||||
|
expect(DateWithPrecision(date, DatePrecision.month).toString(),
|
||||||
|
equals("May 2024"));
|
||||||
|
expect(DateWithPrecision(date, DatePrecision.year).toString(),
|
||||||
|
equals("2024"));
|
||||||
|
expect(DateWithPrecision(date, DatePrecision.decade).toString(),
|
||||||
|
equals("2020s"));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:release_schedule/api/json_helper.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group("selectInJson", () {
|
||||||
|
late Map<String, dynamic> json;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
json = {
|
||||||
|
"a": {
|
||||||
|
"b": [
|
||||||
|
{"c": 1},
|
||||||
|
{"c": 2},
|
||||||
|
{"c": 3},
|
||||||
|
],
|
||||||
|
"c": 4,
|
||||||
|
},
|
||||||
|
"d": [
|
||||||
|
{"e": 5},
|
||||||
|
{"e": 6},
|
||||||
|
{"e": "7"},
|
||||||
|
{"e": 7},
|
||||||
|
]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should select a value", () {
|
||||||
|
expect(selectInJson<int>(json, "a.b.1.c").toList(), equals([2]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should select multiple values", () {
|
||||||
|
expect(selectInJson<int>(json, "a.b.*.c").toList(), equals([1, 2, 3]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should select multiple values with nested lists", () {
|
||||||
|
expect(selectInJson<int>(json, "a.**.c").toList(), equals([4, 1, 2, 3]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should select multiple values with nested lists and maps", () {
|
||||||
|
expect(selectInJson<int>(json, "**.e").toList(), equals([5, 6, 7]));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ void main() {
|
||||||
setUp(() {
|
setUp(() {
|
||||||
movieManager = MovieManager(
|
movieManager = MovieManager(
|
||||||
MovieApi(),
|
MovieApi(),
|
||||||
LocalMovieStorage(),
|
InMemoryMovieStorage(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -64,7 +64,38 @@ void main() {
|
||||||
expect(movieManager.movies, equals([...movies, ...newMovies]));
|
expect(movieManager.movies, equals([...movies, ...newMovies]));
|
||||||
});
|
});
|
||||||
|
|
||||||
test("addMovies should sort movies by their release dates", () {
|
test('addMovies should update existing movies', () {
|
||||||
|
final movies = [
|
||||||
|
MovieData(
|
||||||
|
'The Matrix',
|
||||||
|
DateWithPrecisionAndCountry(DateTime(1999, 3, 31), DatePrecision.day,
|
||||||
|
'United States of America'),
|
||||||
|
),
|
||||||
|
MovieData(
|
||||||
|
'The Matrix Reloaded',
|
||||||
|
DateWithPrecisionAndCountry(DateTime(2003, 5, 7), DatePrecision.day,
|
||||||
|
'United States of America'),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
movieManager.addMovies(movies);
|
||||||
|
|
||||||
|
final updatedMovie = MovieData(
|
||||||
|
'The Matrix Reloaded',
|
||||||
|
DateWithPrecisionAndCountry(DateTime(2003, 5, 7), DatePrecision.day,
|
||||||
|
'United States of America'),
|
||||||
|
)..setDetails(
|
||||||
|
bookmarked: true,
|
||||||
|
genres: ['Action', 'Adventure'],
|
||||||
|
);
|
||||||
|
|
||||||
|
movieManager.addMovies([updatedMovie]);
|
||||||
|
|
||||||
|
expect(movieManager.movies[1].genres, equals(updatedMovie.genres));
|
||||||
|
expect(movieManager.movies[1].bookmarked, equals(false));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('addMovies should sort movies by their release dates', () {
|
||||||
final movies = [
|
final movies = [
|
||||||
MovieData(
|
MovieData(
|
||||||
'The Matrix Reloaded',
|
'The Matrix Reloaded',
|
||||||
|
@ -83,6 +114,27 @@ void main() {
|
||||||
expect(movieManager.movies, equals([...movies.reversed]));
|
expect(movieManager.movies, equals([...movies.reversed]));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'addMovies should sort movies that have a less precise release date before movies with more precise release dates',
|
||||||
|
() {
|
||||||
|
final movies = [
|
||||||
|
MovieData(
|
||||||
|
'The Matrix Reloaded',
|
||||||
|
DateWithPrecisionAndCountry(DateTime(2003, 5, 7), DatePrecision.day,
|
||||||
|
'United States of America'),
|
||||||
|
),
|
||||||
|
MovieData(
|
||||||
|
'The Matrix',
|
||||||
|
DateWithPrecisionAndCountry(DateTime(2003, 5, 7), DatePrecision.month,
|
||||||
|
'United States of America'),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
movieManager.addMovies(movies);
|
||||||
|
|
||||||
|
expect(movieManager.movies, equals([...movies.reversed]));
|
||||||
|
});
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'when a movie is modified and it\'s date is changed the movies should be resorted',
|
'when a movie is modified and it\'s date is changed the movies should be resorted',
|
||||||
() async {
|
() async {
|
||||||
|
@ -136,5 +188,28 @@ void main() {
|
||||||
|
|
||||||
expect(movieManager.movies, equals([notRemoved]));
|
expect(movieManager.movies, equals([notRemoved]));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("localSearch", () {
|
||||||
|
final movies = [
|
||||||
|
MovieData(
|
||||||
|
'The Matrix',
|
||||||
|
DateWithPrecisionAndCountry(DateTime(1999, 3, 31), DatePrecision.day,
|
||||||
|
'United States of America'),
|
||||||
|
),
|
||||||
|
MovieData(
|
||||||
|
'The Matrix Reloaded',
|
||||||
|
DateWithPrecisionAndCountry(DateTime(2003, 5, 7), DatePrecision.day,
|
||||||
|
'United States of America'),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
movieManager.addMovies(movies);
|
||||||
|
|
||||||
|
expect(movieManager.localSearch('Matrix'), equals(movies));
|
||||||
|
expect(movieManager.localSearch('Matrix Re'),
|
||||||
|
equals(movies.reversed.toList()));
|
||||||
|
expect(movieManager.localSearch('Matrix Reloaded'), equals([movies[1]]));
|
||||||
|
expect(movieManager.localSearch('Matrix Revolutions'), equals([]));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,6 @@ void main() {
|
||||||
'Adventure'
|
'Adventure'
|
||||||
], titles: [
|
], titles: [
|
||||||
(title: 'Title 2', language: 'en')
|
(title: 'Title 2', language: 'en')
|
||||||
], reviews: [
|
|
||||||
Review('8.5', 'John Doe', DateTime(2023, 1, 1), 100)
|
|
||||||
]);
|
]);
|
||||||
movie1.updateWithNewIgnoringUserControlled(movie2);
|
movie1.updateWithNewIgnoringUserControlled(movie2);
|
||||||
expect(movie1.title, equals('Title 2'));
|
expect(movie1.title, equals('Title 2'));
|
||||||
|
@ -35,10 +33,6 @@ void main() {
|
||||||
expect(movie1.titles!.length, equals(1));
|
expect(movie1.titles!.length, equals(1));
|
||||||
expect(movie1.titles![0].title, equals('Title 2'));
|
expect(movie1.titles![0].title, equals('Title 2'));
|
||||||
expect(movie1.titles![0].language, equals('en'));
|
expect(movie1.titles![0].language, equals('en'));
|
||||||
expect(movie1.reviews!.length, equals(1));
|
|
||||||
expect(movie1.reviews![0].score, equals('8.5'));
|
|
||||||
expect(movie1.reviews![0].by, equals('John Doe'));
|
|
||||||
expect(movie1.reviews![0].count, equals(100));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('same() returns true for same title and release date', () {
|
test('same() returns true for same title and release date', () {
|
||||||
|
@ -89,8 +83,6 @@ void main() {
|
||||||
'Adventure'
|
'Adventure'
|
||||||
], titles: [
|
], titles: [
|
||||||
(title: 'Title 2', language: 'en')
|
(title: 'Title 2', language: 'en')
|
||||||
], reviews: [
|
|
||||||
Review('8.5', 'John Doe', DateTime(2023, 1, 1), 100)
|
|
||||||
]);
|
]);
|
||||||
final json = movie.toJsonEncodable();
|
final json = movie.toJsonEncodable();
|
||||||
final movie2 = MovieData.fromJsonEncodable(json);
|
final movie2 = MovieData.fromJsonEncodable(json);
|
||||||
|
@ -104,10 +96,6 @@ void main() {
|
||||||
expect(movie2.titles!.length, equals(1));
|
expect(movie2.titles!.length, equals(1));
|
||||||
expect(movie2.titles![0].title, equals('Title 2'));
|
expect(movie2.titles![0].title, equals('Title 2'));
|
||||||
expect(movie2.titles![0].language, equals('en'));
|
expect(movie2.titles![0].language, equals('en'));
|
||||||
expect(movie2.reviews!.length, equals(1));
|
|
||||||
expect(movie2.reviews![0].score, equals('8.5'));
|
|
||||||
expect(movie2.reviews![0].by, equals('John Doe'));
|
|
||||||
expect(movie2.reviews![0].count, equals(100));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toString()', () {
|
test('toString()', () {
|
||||||
|
@ -123,8 +111,6 @@ void main() {
|
||||||
'Adventure'
|
'Adventure'
|
||||||
], titles: [
|
], titles: [
|
||||||
(title: 'Title 2', language: 'en')
|
(title: 'Title 2', language: 'en')
|
||||||
], reviews: [
|
|
||||||
Review('8.5', 'John Doe', DateTime(2023, 1, 1), 100)
|
|
||||||
]);
|
]);
|
||||||
expect(movie.toString(),
|
expect(movie.toString(),
|
||||||
equals('Title 1 (January 1, 2023 (US); Action, Adventure)'));
|
equals('Title 1 (January 1, 2023 (US); Action, Adventure)'));
|
||||||
|
|
|
@ -9,14 +9,16 @@ import 'package:release_schedule/view/movie_manager_list.dart';
|
||||||
void main() {
|
void main() {
|
||||||
group('HomePage', () {
|
group('HomePage', () {
|
||||||
testWidgets('displays title', (WidgetTester tester) async {
|
testWidgets('displays title', (WidgetTester tester) async {
|
||||||
MovieManager movieManager = MovieManager(MovieApi(), LocalMovieStorage());
|
MovieManager movieManager =
|
||||||
|
MovieManager(MovieApi(), InMemoryMovieStorage());
|
||||||
await tester.pumpWidget(MaterialApp(home: HomePage(movieManager)));
|
await tester.pumpWidget(MaterialApp(home: HomePage(movieManager)));
|
||||||
|
|
||||||
expect(find.text('Search'), findsOneWidget);
|
expect(find.text('Search'), findsOneWidget);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('displays list of releases', (WidgetTester tester) async {
|
testWidgets('displays list of releases', (WidgetTester tester) async {
|
||||||
MovieManager movieManager = MovieManager(MovieApi(), LocalMovieStorage());
|
MovieManager movieManager =
|
||||||
|
MovieManager(MovieApi(), InMemoryMovieStorage());
|
||||||
await tester.pumpWidget(MaterialApp(home: HomePage(movieManager)));
|
await tester.pumpWidget(MaterialApp(home: HomePage(movieManager)));
|
||||||
|
|
||||||
expect(find.byType(MovieManagerList), findsOneWidget);
|
expect(find.byType(MovieManagerList), findsOneWidget);
|
||||||
|
|
|
@ -12,7 +12,7 @@ import 'package:release_schedule/view/movie_manager_list.dart';
|
||||||
void main() {
|
void main() {
|
||||||
group('MovieManagerList', () {
|
group('MovieManagerList', () {
|
||||||
testWidgets('displays movie list', (tester) async {
|
testWidgets('displays movie list', (tester) async {
|
||||||
final manager = MovieManager(MovieApi(), LocalMovieStorage());
|
final manager = MovieManager(MovieApi(), InMemoryMovieStorage());
|
||||||
manager.addMovies([
|
manager.addMovies([
|
||||||
MovieData(
|
MovieData(
|
||||||
'Movie 1',
|
'Movie 1',
|
||||||
|
@ -34,7 +34,7 @@ void main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('updates when new movies are added', (tester) async {
|
testWidgets('updates when new movies are added', (tester) async {
|
||||||
final manager = MovieManager(MovieApi(), LocalMovieStorage());
|
final manager = MovieManager(MovieApi(), InMemoryMovieStorage());
|
||||||
manager.addMovies([
|
manager.addMovies([
|
||||||
MovieData(
|
MovieData(
|
||||||
'Movie 1',
|
'Movie 1',
|
||||||
|
|
Loading…
Reference in New Issue