Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tests #5

Merged
merged 19 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# Changelog
## 0.0.2

All notable changes to this project will be documented in this file.
- chore: write tests
- refactor: Created `TenorHttpClient` so testing can be achieved.
- `getGifs` is now `TenorHttpClient().getGifs(...)`
- `serverRequest` is now `TenorHttpClient().request(...)`

The format is based on [Keep a Changelog](https://keepachangelog.com/) and this project adheres to [Semantic Versioning](https://semver.org/).
[All Code Changes](https://github.com/Flyclops/tenor_dart/compare/0.0.1...0.0.2)

## 0.0.1

Expand Down
13 changes: 11 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@

Following these guidelines helps to communicate that you respect the time of the developers managing and developing this open source project. In return, they should reciprocate that respect in addressing your issue, assessing changes, and helping you finalize your pull requests. These are guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.

## How Can You Contribute?

- Pick up any issue marked with "[good first issue](https://github.com/flyclops/tenor_dart/issues?q=is:open+is:issue+label:%22good+first+issue%22)"
- Propose any feature, enhancement
- Report a bug
- Fix a bug
- Write and improve some documentation
- Send in a Pull Request 🙏

## Creating a Pull Request

Before creating a pull request please:
Expand All @@ -12,10 +21,10 @@ Before creating a pull request please:
2. Install all dependencies (`dart packages get` or `pub get`)
3. Squash your commits and ensure you have a meaningful commit message.
4. If you’ve fixed a bug or added code that should be tested, add tests!
5. Ensure the test suite passes.
5. Ensure the test suite passes and has 100% coverage.
6. If you've changed the public API, make sure to update/add documentation.
7. Format your code (`dart format .`)
8. Analyze your code (`dart analyze --fatal-infos --fatal-warnings .`)
8. Analyze your code (`dart analyze --fatal-infos --fatal-warnings lib`)
9. Create the Pull Request.
10. Verify that all status checks are passing.

Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,15 @@ You can see a live example of it in our mobile game [Domino!](https://flyclops.c
## What's next?

- Documentation
- Tests _([Contributions](https://github.com/Flyclops/tenor_dart/blob/main/CONTRIBUTING.md) welcome)_ ^\_^
- Further improvements

## Contributing

If you read this far then you are awesome! There are a multiple ways in which you can [contribute](https://github.com/Flyclops/tenor_dart/blob/main/CONTRIBUTING.md):

- Pick up any issue marked with "[good first issue](https://github.com/flyclops/tenor_dart/issues?q=is:open+is:issue+label:%22good+first+issue%22)"
- Propose any feature, enhancement
- Report a bug
- Fix a bug
- Write and improve some documentation
- Send in a Pull Request 🙏
6 changes: 4 additions & 2 deletions ci/codecov
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
rm -rf coverage
dart test --coverage=./coverage
dart run coverage:format_coverage -i ./coverage -o ./coverage/lcov.info --lcov --check-ignore --report-on lib/
genhtml coverage/lcov.info --output=coverage
open coverage/index.html
genhtml coverage/lcov.info --output=coverage/output
open coverage/output/index.html
# coveralls report coverage/lcov.info --debug --dry-run
3 changes: 0 additions & 3 deletions example/analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,3 @@ linter:
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
10 changes: 9 additions & 1 deletion example/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@
985BD1A59394189F91663605 /* Pods-RunnerTests.release.xcconfig */,
2FF42CF4104BE4FEAF38558A /* Pods-RunnerTests.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
Expand Down Expand Up @@ -468,6 +467,8 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = N6QNV8K6F2;
ENABLE_BITCODE = NO;
Expand All @@ -478,6 +479,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
Expand Down Expand Up @@ -647,6 +649,8 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = N6QNV8K6F2;
ENABLE_BITCODE = NO;
Expand All @@ -657,6 +661,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
Expand All @@ -670,6 +675,8 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = N6QNV8K6F2;
ENABLE_BITCODE = NO;
Expand All @@ -680,6 +687,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
Expand Down
10 changes: 5 additions & 5 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ class _MyHomePageState extends State<MyHomePage> {
Row(
children: searchResults.map(
(gif) {
final tinygif = gif.media.tinygif;
final tinygif = gif.media.tinyGif;
if (tinygif == null) {
return const SizedBox();
}
Expand All @@ -197,7 +197,7 @@ class _MyHomePageState extends State<MyHomePage> {
Row(
children: featuredResults.map(
(gif) {
final tinygif = gif.media.tinygif;
final tinygif = gif.media.tinyGif;
if (tinygif == null) {
return const SizedBox();
}
Expand All @@ -222,7 +222,7 @@ class _MyHomePageState extends State<MyHomePage> {
mainAxisAlignment: MainAxisAlignment.center,
children: postsResults.map(
(gif) {
final tinygif = gif.media.tinygif;
final tinygif = gif.media.tinyGif;
if (tinygif == null) {
return const SizedBox();
}
Expand All @@ -244,9 +244,9 @@ class _MyHomePageState extends State<MyHomePage> {
fontWeight: FontWeight.bold,
),
),
if (randomGif?.media.tinygif?.url != null)
if (randomGif?.media.tinyGif?.url != null)
Image.network(
randomGif!.media.tinygif!.url,
randomGif!.media.tinyGif!.url,
fit: BoxFit.cover,
height: 50,
width: 100,
Expand Down
5 changes: 2 additions & 3 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
name: tenor_dart_example
description: "An example of how to use Tenor Dart"
publish_to: "none" # Remove this line if you wish to publish to pub.dev

version: 1.0.0+1
version: 1.0.0

environment:
sdk: ">=3.2.6 <4.0.0"
sdk: ">=2.17.0 <4.0.0"

dependencies:
flutter:
Expand Down
24 changes: 12 additions & 12 deletions lib/src/constants/media_format.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@
class TenorMediaFormat {
static const String preview = "preview";
static const String gif = "gif";
static const String mediumgif = "mediumgif";
static const String tinygif = "tinygif";
static const String nanogif = "nanogif";
static const String mediumGif = "mediumgif";
static const String tinyGif = "tinygif";
static const String nanoGif = "nanogif";
static const String mp4 = "mp4";
static const String loopedmp4 = "loopedmp4";
static const String tinymp4 = "tinymp4";
static const String nanomp4 = "nanomp4";
static const String loopedMp4 = "loopedmp4";
static const String tinyMp4 = "tinymp4";
static const String nanoMp4 = "nanomp4";
static const String webm = "webm";
static const String tinywebm = "tinywebm";
static const String nanowebm = "nanowebm";
static const String tinyWebm = "tinywebm";
static const String nanoWebm = "nanowebm";
static const String webpTransparent = "webp_transparent";
static const String tinywebpTransparent = "tinywebp_transparent";
static const String nanowebpTransparent = "nanowebp_transparent";
static const String tinyWebpTransparent = "tinywebp_transparent";
static const String nanoWebpTransparent = "nanowebp_transparent";
static const String gifTransparent = "gif_transparent";
static const String tinygifTransparent = "tinygif_transparent";
static const String nanogifTransparent = "nanogif_transparent";
static const String tinyGifTransparent = "tinygif_transparent";
static const String nanoGifTransparent = "nanogif_transparent";
}
2 changes: 2 additions & 0 deletions lib/src/exceptions/api_exception.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ class TenorApiException implements Exception {
this.message,
});

// coverage:ignore-start
@override
String toString() => "TenorApiException code: $code, message: $message";
// coverage:ignore-end
}
104 changes: 104 additions & 0 deletions lib/src/http_client.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import 'dart:async';
import 'dart:convert';

import 'package:http/http.dart' as http;
import 'package:tenor_dart/tenor_dart.dart';

/// A class for handling requests to HTTP.
///
/// Needed as a class so it is easier to test/mock.
class TenorHttpClient {
final http.Client? client;

const TenorHttpClient([
this.client,
]);

http.Client get _client => client ?? http.Client();

// Errors will return error in the body.
// https://developers.google.com/tenor/guides/response-objects-and-errors
Future<Map<String, dynamic>> request(String url, Duration timeout) async {
try {
final response =
await _client.get(Uri.parse(tenorApiUrl + url)).timeout(timeout);
// get json
final Map<String, dynamic> json = jsonDecode(response.body);

// if an error is present, throw it
if (json['error'] != null ||
(response.statusCode != 200 && response.statusCode != 202)) {
throw TenorApiException(
code: response.statusCode,
message: json['error']?['message'],
);
}
// if no error, return the json for consumption
return Future.value({
...json,
// pass timeout back for fetchNext
'timeout': timeout.inMicroseconds,
});
} on TimeoutException {
throw TenorNetworkException();
} on http.ClientException catch (e) {
if (e.runtimeType.toString() == '_ClientSocketException') {
throw TenorNetworkException();
}
rethrow;
} catch (e) {
// let the consumer handle it
rethrow;
}
}

/// Shared functionality between Search and Featured endpoints.
Future<TenorResponse?> getGifs(
TenorEndpoint endPoint,
Duration timeout,
String parameters, {
int limit = 1,
TenorContentFilter? contentFilter,
TenorAspectRatioRange? aspectRatioRange,
List<String>? mediaFilter,
String? pos,
bool sticker = false,
bool random = false,
}) async {
var path = endPoint.name + parameters;

path += '&limit=${limit.clamp(1, 50)}';

if (sticker) {
path += '&searchfilter=sticker';
}
if (random) {
path += '&random=true';
}
if (contentFilter != null) {
path += '&contentfilter=${contentFilter.name}';
}
if (mediaFilter != null) {
path += '&media_filter=${mediaFilter.join(',')}';
}
if (aspectRatioRange != null) {
path += '&ar_range=${aspectRatioRange.name}';
}
if (pos != null) {
path += '&pos=$pos';
}

var data = await request(path, timeout);
TenorResponse? res;
if (data.isNotEmpty) {
res = TenorResponse.fromJson(
{
...data,
'endpoint': endPoint.name,
'parameters': parameters,
},
);
}
return res;
}
}
6 changes: 2 additions & 4 deletions lib/src/models/category.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ part 'category.g.dart';
@JsonSerializable()
class TenorCategory {
static const _encoder = JsonEncoder.withIndent(' ');
static const _decoder = JsonDecoder();

/// The search term that corresponds to the category. The search term is translated to match the locale of the corresponding request.
@JsonKey(name: 'searchterm', disallowNullValue: true)
Expand Down Expand Up @@ -38,9 +37,8 @@ class TenorCategory {

Map<String, dynamic> toJson() => _$TenorCategoryToJson(this);

factory TenorCategory.fromString(String message) =>
TenorCategory.fromJson(_decoder.convert(message));

// coverage:ignore-start
@override
String toString() => _encoder.convert(toJson());
// coverage:ignore-end
}
1 change: 0 additions & 1 deletion lib/src/models/category.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading