tests: add unit tests and fix bugs

main
daniel-michel 2023-11-16 14:38:33 +01:00
parent f5d8e07170
commit c0bd61db05
7 changed files with 363 additions and 42 deletions

View File

@ -1,7 +1,11 @@
import 'package:release_schedule/model/movie.dart';
abstract class MovieApi {
Future<List<MovieData>> getUpcomingMovies(DateTime startDate, [int count]);
Future<List<MovieData>> searchForMovies(String searchTerm);
Future<void> addMovieDetails(List<MovieData> movies);
class MovieApi {
Future<List<MovieData>> getUpcomingMovies(DateTime startDate,
[int count = 10]) async =>
[];
Future<List<MovieData>> searchForMovies(String searchTerm) async => [];
Future<void> addMovieDetails(List<MovieData> movies) async {}
}

View File

@ -14,7 +14,8 @@ String _durationToRelativeDateString(Duration duration) {
return "Yesterday";
}
if (duration.isNegative) {
return "${_durationApproximatedInWords(-duration)} ago";
String result = _durationApproximatedInWords(-duration);
return "${result[0].toUpperCase()}${result.substring(1)} ago";
} else if (duration == Duration.zero) {
return "Today";
} else {

View File

@ -95,12 +95,12 @@ class MovieData extends ChangeNotifier {
"releaseDates": releaseDatesByCountry,
"genres": genres,
"titles": titlesByCountry,
"reviews": reviews,
"reviews": reviews?.map((review) => review.toJsonEncodable()).toList(),
};
}
bool same(MovieData other) {
return title == other.title && releaseDate == other.releaseDate;
return title == other.title && releaseDate.date == other.releaseDate.date;
}
MovieData.fromJsonEncodable(Map json)
@ -112,13 +112,13 @@ class MovieData extends ChangeNotifier {
?.map((genre) => genre as String)
.toList(),
releaseDates: json["releaseDates"] != null
? (json["releaseDates"] as List<List<dynamic>>)
? (json["releaseDates"] as List<dynamic>)
.map((release) =>
DateWithPrecisionAndCountry.fromJsonEncodable(release))
.toList()
: null,
reviews: json["reviews"] != null
? (json["reviews"] as List<Map<String, dynamic>>)
? (json["reviews"] as List<dynamic>)
.map((review) => Review.fromJsonEncodable(review))
.toList()
: null,
@ -155,7 +155,9 @@ class DateWithPrecisionAndCountry {
@override
String toString() {
String dateString = switch (precision) {
DatePrecision.decade || DatePrecision.year => date.year.toString(),
DatePrecision.decade =>
"${DateFormat("yyyy").format(date).substring(0, 3)}0s",
DatePrecision.year => date.year.toString(),
DatePrecision.month => DateFormat("MMMM yyyy").format(date),
DatePrecision.day => DateFormat("MMMM d, yyyy").format(date),
DatePrecision.hour => DateFormat("MMMM d, yyyy, HH").format(date),

View File

@ -21,16 +21,64 @@ void main() {
expect(result, 'Yesterday');
});
test('returns "in X days" for future dates', () {
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 "X days ago" for past dates', () {
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');
});
});
}

View File

@ -0,0 +1,139 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:release_schedule/api/movie_api.dart';
import 'package:release_schedule/model/local_movie_storage.dart';
import 'package:release_schedule/model/movie.dart';
import 'package:release_schedule/model/movie_manager.dart';
void main() {
group('MovieManager', () {
late MovieManager movieManager;
setUp(() {
movieManager = MovieManager(
MovieApi(),
LocalMovieStorage(),
);
});
test('addMovies should add movies to the list', () {
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.movies, equals(movies));
});
test('addMovies should add new 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 newMovies = [
MovieData(
'The Matrix Revolutions',
DateWithPrecisionAndCountry(DateTime(2003, 11, 5), DatePrecision.day,
'United States of America'),
),
];
movieManager.addMovies(newMovies);
expect(movieManager.movies, equals([...movies, ...newMovies]));
});
test("addMovies should sort movies by their release dates", () {
final movies = [
MovieData(
'The Matrix Reloaded',
DateWithPrecisionAndCountry(DateTime(2003, 5, 7), DatePrecision.day,
'United States of America'),
),
MovieData(
'The Matrix',
DateWithPrecisionAndCountry(DateTime(1999, 3, 31), DatePrecision.day,
'United States of America'),
),
];
movieManager.addMovies(movies);
expect(movieManager.movies, equals([...movies.reversed]));
});
test(
'when a movie is modified and it\'s date is changed the movies should be resorted',
() async {
final movies = [
MovieData(
'The Matrix Reloaded',
DateWithPrecisionAndCountry(DateTime(1998, 5, 7), DatePrecision.day,
'United States of America'),
),
MovieData(
'The Matrix',
DateWithPrecisionAndCountry(DateTime(1999, 3, 31), DatePrecision.day,
'United States of America'),
),
];
movieManager.addMovies(movies);
final movie = movieManager.movies.first;
movie.setDetails(
releaseDate: DateWithPrecisionAndCountry(DateTime(2003, 5, 7),
DatePrecision.day, 'United States of America'),
);
await Future.delayed(const Duration(milliseconds: 100));
expect(movieManager.movies, equals([...movies.reversed]));
});
test('removeMoviesWhere should remove movies from the list', () {
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'),
),
];
MovieData notRemoved = MovieData(
'Harry Potter and the Philosopher\'s Stone',
DateWithPrecisionAndCountry(
DateTime(2001, 11, 4), DatePrecision.day, 'United Kingdom'),
);
movieManager.addMovies([...movies, notRemoved]);
movieManager.removeMoviesWhere((movie) => movie.title.contains('Matrix'));
expect(movieManager.movies, equals([notRemoved]));
});
});
}

View File

@ -0,0 +1,157 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:release_schedule/model/movie.dart';
void main() {
group('MovieData', () {
test('updateWithNew() updates all fields', () {
final movie1 = MovieData('Title 1',
DateWithPrecisionAndCountry(DateTime.now(), DatePrecision.day, 'US'));
final movie2 = MovieData('Title 2',
DateWithPrecisionAndCountry(DateTime.now(), DatePrecision.day, 'UK'));
movie2.setDetails(releaseDates: [
DateWithPrecisionAndCountry(DateTime.now(), DatePrecision.day, 'US')
], genres: [
'Action',
'Adventure'
], titles: [
(title: 'Title 2', language: 'en')
], reviews: [
Review('8.5', 'John Doe', DateTime.now(), 100)
]);
movie1.updateWithNew(movie2);
expect(movie1.title, equals('Title 2'));
expect(movie1.releaseDate.country, equals('UK'));
expect(movie1.releaseDates!.length, equals(1));
expect(movie1.releaseDates![0].country, equals('US'));
expect(movie1.genres!.length, equals(2));
expect(movie1.genres![0], equals('Action'));
expect(movie1.genres![1], equals('Adventure'));
expect(movie1.titles!.length, equals(1));
expect(movie1.titles![0].title, equals('Title 2'));
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', () {
final movie1 = MovieData(
'Title 1',
DateWithPrecisionAndCountry(
DateTime(2023, 1, 1), DatePrecision.day, 'US'));
final movie2 = MovieData(
'Title 1',
DateWithPrecisionAndCountry(
DateTime(2023, 1, 1), DatePrecision.day, 'US'));
expect(movie1.same(movie2), isTrue);
});
test('same() returns false for different title', () {
final movie1 = MovieData(
'Title 1',
DateWithPrecisionAndCountry(
DateTime(2023, 1, 1), DatePrecision.day, 'US'));
final movie2 = MovieData(
'Title 2',
DateWithPrecisionAndCountry(
DateTime(2023, 1, 1), DatePrecision.day, 'US'));
expect(movie1.same(movie2), isFalse);
});
test('same() returns false for different release date', () {
final movie1 = MovieData(
'Title 1',
DateWithPrecisionAndCountry(
DateTime(2023, 1, 1), DatePrecision.day, 'US'));
final movie2 = MovieData(
'Title 1',
DateWithPrecisionAndCountry(
DateTime(2023, 1, 2), DatePrecision.day, 'US'));
expect(movie1.same(movie2), isFalse);
});
test('can be encoded to JSON and back', () {
final movie = MovieData('Title 1',
DateWithPrecisionAndCountry(DateTime.now(), DatePrecision.day, 'US'));
movie.setDetails(releaseDates: [
DateWithPrecisionAndCountry(DateTime.now(), DatePrecision.day, 'US')
], genres: [
'Action',
'Adventure'
], titles: [
(title: 'Title 2', language: 'en')
], reviews: [
Review('8.5', 'John Doe', DateTime.now(), 100)
]);
final json = movie.toJsonEncodable();
final movie2 = MovieData.fromJsonEncodable(json);
expect(movie2.title, equals('Title 1'));
expect(movie2.releaseDate.country, equals('US'));
expect(movie2.releaseDates!.length, equals(1));
expect(movie2.releaseDates![0].country, equals('US'));
expect(movie2.genres!.length, equals(2));
expect(movie2.genres![0], equals('Action'));
expect(movie2.genres![1], equals('Adventure'));
expect(movie2.titles!.length, equals(1));
expect(movie2.titles![0].title, equals('Title 2'));
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()', () {
final movie = MovieData('Title 1',
DateWithPrecisionAndCountry(DateTime.now(), DatePrecision.day, 'US'));
movie.setDetails(releaseDates: [
DateWithPrecisionAndCountry(DateTime.now(), DatePrecision.day, 'US')
], genres: [
'Action',
'Adventure'
], titles: [
(title: 'Title 2', language: 'en')
], reviews: [
Review('8.5', 'John Doe', DateTime.now(), 100)
]);
expect(movie.toString(),
equals('Title 1 (November 16, 2023 (US); Action, Adventure)'));
});
});
group('DateWithPrecisionAndCountry', () {
test('can be encoded to JSON and back', () {
final date =
DateWithPrecisionAndCountry(DateTime.now(), DatePrecision.day, 'US');
final json = date.toJsonEncodable();
final date2 = DateWithPrecisionAndCountry.fromJsonEncodable(json);
expect(date2.date, equals(date.date));
expect(date2.precision, equals(date.precision));
expect(date2.country, equals(date.country));
});
test('toString()', () {
final date = DateWithPrecisionAndCountry(
DateTime(2023, 1, 1), DatePrecision.day, 'US');
expect(date.toString(), equals('January 1, 2023 (US)'));
});
test('toString() with month precision', () {
final date = DateWithPrecisionAndCountry(
DateTime(2023, 1, 1), DatePrecision.month, 'US');
expect(date.toString(), equals('January 2023 (US)'));
});
test('toString() with year precision', () {
final date = DateWithPrecisionAndCountry(
DateTime(2023, 1, 1), DatePrecision.year, 'US');
expect(date.toString(), equals('2023 (US)'));
});
test('toString() with decade precision', () {
final date = DateWithPrecisionAndCountry(
DateTime(2023, 1, 1), DatePrecision.decade, 'US');
expect(date.toString(), equals('2020s (US)'));
});
});
}

View File

@ -1,30 +0,0 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility in the flutter_test package. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:release_schedule/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}