Support FirebaseStorage with custom Firebase app (#524)
diff --git a/packages/firebase_storage/CHANGELOG.md b/packages/firebase_storage/CHANGELOG.md index 379ebb4..f9a1739 100644 --- a/packages/firebase_storage/CHANGELOG.md +++ b/packages/firebase_storage/CHANGELOG.md
@@ -1,3 +1,7 @@ +## 0.3.3 + +* Added support for initialization with a custom Firebase app. + ## 0.3.2 * Added support for StorageReference `writeToFile`.
diff --git a/packages/firebase_storage/android/src/main/java/io/flutter/plugins/firebase/storage/FirebaseStoragePlugin.java b/packages/firebase_storage/android/src/main/java/io/flutter/plugins/firebase/storage/FirebaseStoragePlugin.java index f927bbf..46318d9 100755 --- a/packages/firebase_storage/android/src/main/java/io/flutter/plugins/firebase/storage/FirebaseStoragePlugin.java +++ b/packages/firebase_storage/android/src/main/java/io/flutter/plugins/firebase/storage/FirebaseStoragePlugin.java
@@ -36,11 +36,22 @@ private FirebaseStoragePlugin(Registrar registrar) { FirebaseApp.initializeApp(registrar.context()); - this.firebaseStorage = FirebaseStorage.getInstance(); } @Override public void onMethodCall(MethodCall call, final Result result) { + String app = call.argument("app"); + String storageBucket = call.argument("bucket"); + if (app == null && storageBucket == null) { + firebaseStorage = FirebaseStorage.getInstance(); + } else if (storageBucket == null) { + firebaseStorage = FirebaseStorage.getInstance(FirebaseApp.getInstance(app)); + } else if (app == null) { + firebaseStorage = FirebaseStorage.getInstance(storageBucket); + } else { + firebaseStorage = FirebaseStorage.getInstance(FirebaseApp.getInstance(app), storageBucket); + } + switch (call.method) { case "StorageReference#putFile": putFile(call, result);
diff --git a/packages/firebase_storage/example/lib/main.dart b/packages/firebase_storage/example/lib/main.dart index 2a6169e..6fcc752 100755 --- a/packages/firebase_storage/example/lib/main.dart +++ b/packages/firebase_storage/example/lib/main.dart
@@ -7,24 +7,44 @@ import 'dart:math'; import 'package:flutter/material.dart'; +import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:http/http.dart' as http; -void main() { - runApp(new MyApp()); +void main() async { + final FirebaseApp app = await FirebaseApp.configure( + name: 'test', + options: new FirebaseOptions( + googleAppID: Platform.isIOS + ? '1:159623150305:ios:4a213ef3dbd8997b' + : '1:159623150305:android:ef48439a0cc0263d', + gcmSenderID: '159623150305', + apiKey: 'AIzaSyChk3KEG7QYrs4kQPLP1tjJNxBTbfCAdgg', + projectID: 'flutter-firebase-plugins', + ), + ); + final FirebaseStorage storage = new FirebaseStorage( + app: app, storageBucket: 'gs://flutter-firebase-plugins.appspot.com'); + runApp(new MyApp(storage: storage)); } class MyApp extends StatelessWidget { + MyApp({this.storage}); + final FirebaseStorage storage; + @override Widget build(BuildContext context) { return new MaterialApp( title: 'Flutter Storage Example', - home: new MyHomePage(), + home: new MyHomePage(storage: storage), ); } } class MyHomePage extends StatefulWidget { + MyHomePage({this.storage}); + final FirebaseStorage storage; + @override _MyHomePageState createState() => new _MyHomePageState(); } @@ -45,7 +65,7 @@ assert(await file.readAsString() == kTestString); final String rand = "${new Random().nextInt(10000)}"; final StorageReference ref = - FirebaseStorage.instance.ref().child('text').child('foo$rand.txt'); + widget.storage.ref().child('text').child('foo$rand.txt'); final StorageUploadTask uploadTask = ref.putFile(file, const StorageMetadata(contentLanguage: "en"));
diff --git a/packages/firebase_storage/ios/Classes/FirebaseStoragePlugin.m b/packages/firebase_storage/ios/Classes/FirebaseStoragePlugin.m index c00a089..1e20e59 100644 --- a/packages/firebase_storage/ios/Classes/FirebaseStoragePlugin.m +++ b/packages/firebase_storage/ios/Classes/FirebaseStoragePlugin.m
@@ -19,6 +19,7 @@ @end @implementation FLTFirebaseStoragePlugin { + FIRStorage *storage; } + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar { @@ -40,6 +41,18 @@ } - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { + NSString *appName = call.arguments[@"app"]; + NSString *storageBucket = call.arguments[@"bucket"]; + if ([appName isEqual:[NSNull null]] && [storageBucket isEqual:[NSNull null]]) { + storage = [FIRStorage storage]; + } else if ([appName isEqual:[NSNull null]]) { + storage = [FIRStorage storageWithURL:storageBucket]; + } else if ([storageBucket isEqual:[NSNull null]]) { + storage = [FIRStorage storageForApp:[FIRApp appNamed:appName]]; + } else { + storage = [FIRStorage storageForApp:[FIRApp appNamed:appName] URL:storageBucket]; + } + if ([@"StorageReference#putFile" isEqualToString:call.method]) { [self putFile:call result:result]; } else if ([@"StorageReference#putData" isEqualToString:call.method]) { @@ -84,7 +97,7 @@ if (![metadataDictionary isEqual:[NSNull null]]) { metadata = [self buildMetadataFromDictionary:metadataDictionary]; } - FIRStorageReference *fileRef = [[FIRStorage storage].reference child:path]; + FIRStorageReference *fileRef = [storage.reference child:path]; [fileRef putData:data metadata:metadata completion:^(FIRStorageMetadata *metadata, NSError *error) { @@ -140,7 +153,7 @@ - (void)getData:(FlutterMethodCall *)call result:(FlutterResult)result { NSNumber *maxSize = call.arguments[@"maxSize"]; NSString *path = call.arguments[@"path"]; - FIRStorageReference *ref = [[FIRStorage storage].reference child:path]; + FIRStorageReference *ref = [storage.reference child:path]; [ref dataWithMaxSize:[maxSize longLongValue] completion:^(NSData *_Nullable data, NSError *_Nullable error) { if (error != nil) { @@ -162,7 +175,7 @@ NSString *path = call.arguments[@"path"]; NSString *filePath = call.arguments[@"filePath"]; NSURL *localURL = [NSURL fileURLWithPath:filePath]; - FIRStorageReference *ref = [[FIRStorage storage].reference child:path]; + FIRStorageReference *ref = [storage.reference child:path]; FIRStorageDownloadTask *task = [ref writeToFile:localURL]; [task observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) { @@ -178,7 +191,7 @@ - (void)getMetadata:(FlutterMethodCall *)call result:(FlutterResult)result { NSString *path = call.arguments[@"path"]; - FIRStorageReference *ref = [[FIRStorage storage].reference child:path]; + FIRStorageReference *ref = [storage.reference child:path]; [ref metadataWithCompletion:^(FIRStorageMetadata *metadata, NSError *error) { if (error != nil) { result(error.flutterError); @@ -191,7 +204,7 @@ - (void)updateMetadata:(FlutterMethodCall *)call result:(FlutterResult)result { NSString *path = call.arguments[@"path"]; NSDictionary *metadataDictionary = call.arguments[@"metadata"]; - FIRStorageReference *ref = [[FIRStorage storage].reference child:path]; + FIRStorageReference *ref = [storage.reference child:path]; [ref updateMetadata:[self buildMetadataFromDictionary:metadataDictionary] completion:^(FIRStorageMetadata *metadata, NSError *error) { if (error != nil) { @@ -204,25 +217,25 @@ - (void)getBucket:(FlutterMethodCall *)call result:(FlutterResult)result { NSString *path = call.arguments[@"path"]; - FIRStorageReference *ref = [[FIRStorage storage].reference child:path]; + FIRStorageReference *ref = [storage.reference child:path]; result([ref bucket]); } - (void)getName:(FlutterMethodCall *)call result:(FlutterResult)result { NSString *path = call.arguments[@"path"]; - FIRStorageReference *ref = [[FIRStorage storage].reference child:path]; + FIRStorageReference *ref = [storage.reference child:path]; result([ref name]); } - (void)getPath:(FlutterMethodCall *)call result:(FlutterResult)result { NSString *path = call.arguments[@"path"]; - FIRStorageReference *ref = [[FIRStorage storage].reference child:path]; + FIRStorageReference *ref = [storage.reference child:path]; result([ref fullPath]); } - (void)getDownloadUrl:(FlutterMethodCall *)call result:(FlutterResult)result { NSString *path = call.arguments[@"path"]; - FIRStorageReference *ref = [[FIRStorage storage].reference child:path]; + FIRStorageReference *ref = [storage.reference child:path]; [ref downloadURLWithCompletion:^(NSURL *URL, NSError *error) { if (error != nil) { result(error.flutterError); @@ -234,7 +247,7 @@ - (void) delete:(FlutterMethodCall *)call result:(FlutterResult)result { NSString *path = call.arguments[@"path"]; - FIRStorageReference *ref = [[FIRStorage storage].reference child:path]; + FIRStorageReference *ref = [storage.reference child:path]; [ref deleteWithCompletion:^(NSError *error) { if (error != nil) { result(error.flutterError);
diff --git a/packages/firebase_storage/lib/firebase_storage.dart b/packages/firebase_storage/lib/firebase_storage.dart index 8979ca9..82fca5f 100755 --- a/packages/firebase_storage/lib/firebase_storage.dart +++ b/packages/firebase_storage/lib/firebase_storage.dart
@@ -7,16 +7,43 @@ import 'dart:typed_data'; import 'package:flutter/services.dart'; +import 'package:firebase_core/firebase_core.dart'; +/// FirebaseStorage is a service that supports uploading and downloading large +/// objects to Google Cloud Storage. class FirebaseStorage { static const MethodChannel channel = const MethodChannel('plugins.flutter.io/firebase_storage'); - static FirebaseStorage get instance => new FirebaseStorage(); + /// Returns the [FirebaseStorage] instance, initialized with a custom + /// [FirebaseApp] if [app] is specified and a custom Google Cloud Storage + /// bucket if [storageBucket] is specified. + /// + /// The [storageBucket] argument is the gs:// url to the custom Firebase + /// Storage Bucket. + /// + /// The [app] argument is the custom [FirebaseApp]. + FirebaseStorage({this.app, this.storageBucket}); - StorageReference ref() { - return new StorageReference._(const <String>[], this); - } + static FirebaseStorage _instance = new FirebaseStorage(); + + /// The [FirebaseApp] instance to which this [FirebaseStorage] belongs. + /// + /// If null, the default [FirebaseApp] is used. + final FirebaseApp app; + + /// The Google Cloud Storage bucket to which this [FirebaseStorage] belongs. + /// + /// If null, the storage bucket of the specified [FirebaseApp] is used. + final String storageBucket; + + /// Returns the [FirebaseStorage] instance, initialized with the default + /// [FirebaseApp]. + static FirebaseStorage get instance => _instance; + + /// Creates a new [StorageReference] initialized at the root + /// Firebase Storage location. + StorageReference ref() => new StorageReference._(const <String>[], this); } class StorageReference { @@ -73,8 +100,8 @@ /// Asynchronously uploads a file to the currently specified /// [StorageReference], with an optional [metadata]. StorageUploadTask putFile(File file, [StorageMetadata metadata]) { - final StorageFileUploadTask task = - new StorageFileUploadTask._(file, _pathComponents.join("/"), metadata); + final StorageFileUploadTask task = new StorageFileUploadTask._( + file, _firebaseStorage, _pathComponents.join("/"), metadata); task._start(); return task; } @@ -82,8 +109,8 @@ /// Asynchronously uploads byte data to the currently specified /// [StorageReference], with an optional [metadata]. StorageUploadTask putData(Uint8List data, [StorageMetadata metadata]) { - final StorageUploadTask task = - new StorageDataUploadTask._(data, _pathComponents.join("/"), metadata); + final StorageUploadTask task = new StorageDataUploadTask._( + data, _firebaseStorage, _pathComponents.join("/"), metadata); task._start(); return task; } @@ -92,6 +119,8 @@ Future<String> getBucket() async { return await FirebaseStorage.channel .invokeMethod("StorageReference#getBucket", <String, String>{ + 'app': _firebaseStorage.app?.name, + 'bucket': _firebaseStorage.storageBucket, 'path': _pathComponents.join("/"), }); } @@ -101,6 +130,8 @@ Future<String> getPath() async { return await FirebaseStorage.channel .invokeMethod("StorageReference#getPath", <String, String>{ + 'app': _firebaseStorage.app?.name, + 'bucket': _firebaseStorage.storageBucket, 'path': _pathComponents.join("/"), }); } @@ -109,6 +140,8 @@ Future<String> getName() async { return await FirebaseStorage.channel .invokeMethod("StorageReference#getName", <String, String>{ + 'app': _firebaseStorage.app?.name, + 'bucket': _firebaseStorage.storageBucket, 'path': _pathComponents.join("/"), }); } @@ -119,6 +152,8 @@ return await FirebaseStorage.channel.invokeMethod( "StorageReference#getData", <String, dynamic>{ + 'app': _firebaseStorage.app?.name, + 'bucket': _firebaseStorage.storageBucket, 'maxSize': maxSize, 'path': _pathComponents.join("/"), }, @@ -128,8 +163,8 @@ /// Asynchronously downloads the object at this [StorageReference] to a /// specified system file. StorageFileDownloadTask writeToFile(File file) { - final StorageFileDownloadTask task = - new StorageFileDownloadTask._(_pathComponents.join("/"), file); + final StorageFileDownloadTask task = new StorageFileDownloadTask._( + _firebaseStorage, _pathComponents.join("/"), file); task._start(); return task; } @@ -140,19 +175,27 @@ Future<dynamic> getDownloadURL() async { return await FirebaseStorage.channel .invokeMethod("StorageReference#getDownloadUrl", <String, String>{ + 'app': _firebaseStorage.app?.name, + 'bucket': _firebaseStorage.storageBucket, 'path': _pathComponents.join("/"), }); } Future<void> delete() { - return FirebaseStorage.channel.invokeMethod("StorageReference#delete", - <String, String>{'path': _pathComponents.join("/")}); + return FirebaseStorage.channel + .invokeMethod("StorageReference#delete", <String, String>{ + 'app': _firebaseStorage.app?.name, + 'bucket': _firebaseStorage.storageBucket, + 'path': _pathComponents.join("/") + }); } /// Retrieves metadata associated with an object at this [StorageReference]. Future<StorageMetadata> getMetadata() async { return new StorageMetadata._fromMap(await FirebaseStorage.channel .invokeMethod("StorageReference#getMetadata", <String, String>{ + 'app': _firebaseStorage.app?.name, + 'bucket': _firebaseStorage.storageBucket, 'path': _pathComponents.join("/"), })); } @@ -167,6 +210,8 @@ Future<StorageMetadata> updateMetadata(StorageMetadata metadata) async { return new StorageMetadata._fromMap(await FirebaseStorage.channel .invokeMethod("StorageReference#updateMetadata", <String, dynamic>{ + 'app': _firebaseStorage.app?.name, + 'bucket': _firebaseStorage.storageBucket, 'path': _pathComponents.join("/"), 'metadata': metadata == null ? null : _buildMetadataUploadMap(metadata), })); @@ -255,15 +300,18 @@ } class StorageFileDownloadTask { + final FirebaseStorage _firebaseStorage; final String _path; final File _file; - StorageFileDownloadTask._(this._path, this._file); + StorageFileDownloadTask._(this._firebaseStorage, this._path, this._file); Future<void> _start() async { final int totalByteCount = await FirebaseStorage.channel.invokeMethod( "StorageReference#writeToFile", <String, dynamic>{ + 'app': _firebaseStorage.app?.name, + 'bucket': _firebaseStorage.storageBucket, 'filePath': _file.absolute.path, 'path': _path, }, @@ -278,10 +326,11 @@ } abstract class StorageUploadTask { + final FirebaseStorage _firebaseStorage; final String _path; final StorageMetadata _metadata; - StorageUploadTask._(this._path, this._metadata); + StorageUploadTask._(this._firebaseStorage, this._path, this._metadata); Future<void> _start(); Completer<UploadTaskSnapshot> _completer = @@ -291,14 +340,17 @@ class StorageFileUploadTask extends StorageUploadTask { final File _file; - StorageFileUploadTask._(this._file, String path, StorageMetadata metadata) - : super._(path, metadata); + StorageFileUploadTask._(this._file, FirebaseStorage firebaseStorage, + String path, StorageMetadata metadata) + : super._(firebaseStorage, path, metadata); @override Future<void> _start() async { final String downloadUrl = await FirebaseStorage.channel.invokeMethod( 'StorageReference#putFile', <String, dynamic>{ + 'app': _firebaseStorage.app?.name, + 'bucket': _firebaseStorage.storageBucket, 'filename': _file.absolute.path, 'path': _path, 'metadata': @@ -312,14 +364,17 @@ class StorageDataUploadTask extends StorageUploadTask { final Uint8List _bytes; - StorageDataUploadTask._(this._bytes, String path, StorageMetadata metadata) - : super._(path, metadata); + StorageDataUploadTask._(this._bytes, FirebaseStorage firebaseStorage, + String path, StorageMetadata metadata) + : super._(firebaseStorage, path, metadata); @override Future<void> _start() async { final String downloadUrl = await FirebaseStorage.channel.invokeMethod( 'StorageReference#putData', <String, dynamic>{ + 'app': _firebaseStorage.app?.name, + 'bucket': _firebaseStorage.storageBucket, 'data': _bytes, 'path': _path, 'metadata':
diff --git a/packages/firebase_storage/pubspec.yaml b/packages/firebase_storage/pubspec.yaml index 17eb3fd..c168813 100755 --- a/packages/firebase_storage/pubspec.yaml +++ b/packages/firebase_storage/pubspec.yaml
@@ -3,7 +3,7 @@ cost-effective object storage service for Android and iOS. author: Flutter Team <flutter-dev@googlegroups.com> homepage: https://github.com/flutter/plugins/tree/master/packages/firebase_storage -version: 0.3.2 +version: 0.3.3 flutter: plugin: @@ -14,6 +14,7 @@ dependencies: flutter: sdk: flutter + firebase_core: ^0.2.3 dev_dependencies: flutter_test:
diff --git a/packages/firebase_storage/test/firebase_storage_test.dart b/packages/firebase_storage/test/firebase_storage_test.dart index ea23737..1697821 100644 --- a/packages/firebase_storage/test/firebase_storage_test.dart +++ b/packages/firebase_storage/test/firebase_storage_test.dart
@@ -5,217 +5,296 @@ import 'dart:async'; import 'dart:typed_data'; +import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { - group('StorageReference', () { - group('getData', () { - final List<MethodCall> log = <MethodCall>[]; + group('FirebaseStorage', () { + final FirebaseApp app = const FirebaseApp( + name: 'testApp', + ); + final String storageBucket = 'gs://fake-storage-bucket-url.com'; + final FirebaseStorage storage = + new FirebaseStorage(app: app, storageBucket: storageBucket); - StorageReference ref; + group('StorageReference', () { + group('getData', () { + final List<MethodCall> log = <MethodCall>[]; - setUp(() { - FirebaseStorage.channel - .setMockMethodCallHandler((MethodCall methodCall) { - log.add(methodCall); - return new Future<Uint8List>.value( - new Uint8List.fromList(<int>[1, 2, 3, 4])); + StorageReference ref; + + setUp(() { + FirebaseStorage.channel + .setMockMethodCallHandler((MethodCall methodCall) { + log.add(methodCall); + return new Future<Uint8List>.value( + new Uint8List.fromList(<int>[1, 2, 3, 4])); + }); + ref = + storage.ref().child('avatars').child('large').child('image.jpg'); }); - ref = FirebaseStorage.instance - .ref() - .child('avatars') - .child('large') - .child('image.jpg'); - }); - test('invokes correct method', () async { - await ref.getData(10); + test('invokes correct method', () async { + await ref.getData(10); - expect(log, <Matcher>[ - isMethodCall( - 'StorageReference#getData', - arguments: <String, dynamic>{ - 'maxSize': 10, - 'path': 'avatars/large/image.jpg', - }, - ), - ]); - }); - - test('returns correct result', () async { - expect(await ref.getData(10), - equals(new Uint8List.fromList(<int>[1, 2, 3, 4]))); - }); - }); - - group('getMetadata', () { - final List<MethodCall> log = <MethodCall>[]; - - StorageReference ref; - - setUp(() { - FirebaseStorage.channel - .setMockMethodCallHandler((MethodCall methodCall) async { - log.add(methodCall); - return <String, String>{'name': 'image.jpg'}; - }); - ref = FirebaseStorage.instance - .ref() - .child('avatars') - .child('large') - .child('image.jpg'); - }); - - test('invokes correct method', () async { - await ref.getMetadata(); - - expect(log, <Matcher>[ - isMethodCall( - 'StorageReference#getMetadata', - arguments: <String, dynamic>{ - 'path': 'avatars/large/image.jpg', - }, - ), - ]); - }); - - test('returns correct result', () async { - expect((await ref.getMetadata()).name, 'image.jpg'); - }); - }); - - group('updateMetadata', () { - final List<MethodCall> log = <MethodCall>[]; - - StorageReference ref; - - setUp(() { - FirebaseStorage.channel - .setMockMethodCallHandler((MethodCall methodCall) async { - log.add(methodCall); - switch (methodCall.method) { - case 'StorageReference#getMetadata': - return <String, String>{ - 'name': 'image.jpg', - }; - break; - case 'StorageReference#updateMetadata': - return <String, String>{ - 'name': 'image.jpg', - 'contentLanguage': 'en' - }; - break; - default: - break; - } - }); - ref = FirebaseStorage.instance - .ref() - .child('avatars') - .child('large') - .child('image.jpg'); - }); - - test('invokes correct method', () async { - await ref.updateMetadata(const StorageMetadata(contentLanguage: 'en')); - - expect(log, <Matcher>[ - isMethodCall( - 'StorageReference#updateMetadata', - arguments: <String, dynamic>{ - 'path': 'avatars/large/image.jpg', - 'metadata': <String, String>{ - 'cacheControl': null, - 'contentDisposition': null, - 'contentLanguage': 'en', - 'contentType': null, - 'contentEncoding': null - }, - }, - ), - ]); - }); - - test('returns correct result', () async { - expect((await ref.getMetadata()).contentLanguage, null); - expect( - (await ref.updateMetadata( - const StorageMetadata(contentLanguage: 'en'))) - .contentLanguage, - 'en'); - }); - }); - - group('getDownloadUrl', () { - final List<MethodCall> log = <MethodCall>[]; - - StorageReference ref; - - setUp(() { - FirebaseStorage.channel - .setMockMethodCallHandler((MethodCall methodCall) async { - log.add(methodCall); - return 'https://path/to/file'; - }); - ref = FirebaseStorage.instance - .ref() - .child('avatars') - .child('large') - .child('image.jpg'); - }); - - test('invokes correct method', () async { - await ref.getDownloadURL(); - - expect(log, <Matcher>[ - isMethodCall( - 'StorageReference#getDownloadUrl', - arguments: <String, dynamic>{ - 'path': 'avatars/large/image.jpg', - }, - ), - ]); - }); - - test('returns correct result', () async { - expect(await ref.getDownloadURL(), 'https://path/to/file'); - }); - }); - - group('delete', () { - final List<MethodCall> log = <MethodCall>[]; - - StorageReference ref; - - setUp(() { - FirebaseStorage.channel - .setMockMethodCallHandler((MethodCall methodCall) async { - log.add(methodCall); - return null; - }); - ref = FirebaseStorage.instance.ref().child('image.jpg'); - }); - - test('invokes correct method', () async { - await ref.delete(); - - expect( - log, - <Matcher>[ + expect(log, <Matcher>[ isMethodCall( - 'StorageReference#delete', + 'StorageReference#getData', arguments: <String, dynamic>{ - 'path': 'image.jpg', + 'app': 'testApp', + 'bucket': 'gs://fake-storage-bucket-url.com', + 'maxSize': 10, + 'path': 'avatars/large/image.jpg', }, ), - ], - ); + ]); + }); + + test('returns correct result', () async { + expect(await ref.getData(10), + equals(new Uint8List.fromList(<int>[1, 2, 3, 4]))); + }); + }); + + group('getMetadata', () { + final List<MethodCall> log = <MethodCall>[]; + + StorageReference ref; + + setUp(() { + FirebaseStorage.channel + .setMockMethodCallHandler((MethodCall methodCall) async { + log.add(methodCall); + return <String, String>{'name': 'image.jpg'}; + }); + ref = + storage.ref().child('avatars').child('large').child('image.jpg'); + }); + + test('invokes correct method', () async { + await ref.getMetadata(); + + expect(log, <Matcher>[ + isMethodCall( + 'StorageReference#getMetadata', + arguments: <String, dynamic>{ + 'app': 'testApp', + 'bucket': 'gs://fake-storage-bucket-url.com', + 'path': 'avatars/large/image.jpg', + }, + ), + ]); + }); + + test('returns correct result', () async { + expect((await ref.getMetadata()).name, 'image.jpg'); + }); + }); + + group('updateMetadata', () { + final List<MethodCall> log = <MethodCall>[]; + + StorageReference ref; + + setUp(() { + FirebaseStorage.channel + .setMockMethodCallHandler((MethodCall methodCall) async { + log.add(methodCall); + switch (methodCall.method) { + case 'StorageReference#getMetadata': + return <String, String>{ + 'name': 'image.jpg', + }; + break; + case 'StorageReference#updateMetadata': + return <String, String>{ + 'name': 'image.jpg', + 'contentLanguage': 'en' + }; + break; + default: + break; + } + }); + ref = + storage.ref().child('avatars').child('large').child('image.jpg'); + }); + + test('invokes correct method', () async { + await ref + .updateMetadata(const StorageMetadata(contentLanguage: 'en')); + + expect(log, <Matcher>[ + isMethodCall( + 'StorageReference#updateMetadata', + arguments: <String, dynamic>{ + 'app': 'testApp', + 'bucket': 'gs://fake-storage-bucket-url.com', + 'path': 'avatars/large/image.jpg', + 'metadata': <String, String>{ + 'cacheControl': null, + 'contentDisposition': null, + 'contentLanguage': 'en', + 'contentType': null, + 'contentEncoding': null + }, + }, + ), + ]); + }); + + test('returns correct result', () async { + expect((await ref.getMetadata()).contentLanguage, null); + expect( + (await ref.updateMetadata( + const StorageMetadata(contentLanguage: 'en'))) + .contentLanguage, + 'en'); + }); + }); + + group('getDownloadUrl', () { + final List<MethodCall> log = <MethodCall>[]; + + StorageReference ref; + + setUp(() { + FirebaseStorage.channel + .setMockMethodCallHandler((MethodCall methodCall) async { + log.add(methodCall); + return 'https://path/to/file'; + }); + ref = + storage.ref().child('avatars').child('large').child('image.jpg'); + }); + + test('invokes correct method', () async { + await ref.getDownloadURL(); + + expect(log, <Matcher>[ + isMethodCall( + 'StorageReference#getDownloadUrl', + arguments: <String, dynamic>{ + 'app': 'testApp', + 'bucket': 'gs://fake-storage-bucket-url.com', + 'path': 'avatars/large/image.jpg', + }, + ), + ]); + }); + + test('returns correct result', () async { + expect(await ref.getDownloadURL(), 'https://path/to/file'); + }); + }); + + group('delete', () { + final List<MethodCall> log = <MethodCall>[]; + + StorageReference ref; + + setUp(() { + FirebaseStorage.channel + .setMockMethodCallHandler((MethodCall methodCall) async { + log.add(methodCall); + return null; + }); + ref = storage.ref().child('image.jpg'); + }); + + test('invokes correct method', () async { + await ref.delete(); + + expect( + log, + <Matcher>[ + isMethodCall( + 'StorageReference#delete', + arguments: <String, dynamic>{ + 'app': 'testApp', + 'bucket': 'gs://fake-storage-bucket-url.com', + 'path': 'image.jpg', + }, + ), + ], + ); + }); + }); + + group('getBucket', () { + final List<MethodCall> log = <MethodCall>[]; + + StorageReference ref; + + setUp(() { + FirebaseStorage.channel + .setMockMethodCallHandler((MethodCall methodCall) async { + log.add(methodCall); + return 'foo'; + }); + ref = + storage.ref().child('avatars').child('large').child('image.jpg'); + }); + + test('invokes correct method', () async { + await ref.getBucket(); + + expect(log, <Matcher>[ + isMethodCall( + 'StorageReference#getBucket', + arguments: <String, dynamic>{ + 'app': 'testApp', + 'bucket': 'gs://fake-storage-bucket-url.com', + 'path': 'avatars/large/image.jpg', + }, + ), + ]); + }); + + test('returns correct result', () async { + expect(await ref.getBucket(), 'foo'); + }); + }); + + group('getName', () { + final List<MethodCall> log = <MethodCall>[]; + + StorageReference ref; + + setUp(() { + FirebaseStorage.channel + .setMockMethodCallHandler((MethodCall methodCall) async { + log.add(methodCall); + return 'image.jpg'; + }); + ref = + storage.ref().child('avatars').child('large').child('image.jpg'); + }); + + test('invokes correct method', () async { + await ref.getName(); + + expect(log, <Matcher>[ + isMethodCall( + 'StorageReference#getName', + arguments: <String, dynamic>{ + 'app': 'testApp', + 'bucket': 'gs://fake-storage-bucket-url.com', + 'path': 'avatars/large/image.jpg', + }, + ), + ]); + }); + + test('returns correct result', () async { + expect(await ref.getName(), 'image.jpg'); + }); }); }); - group('getBucket', () { + group('getPath', () { final List<MethodCall> log = <MethodCall>[]; StorageReference ref; @@ -224,22 +303,20 @@ FirebaseStorage.channel .setMockMethodCallHandler((MethodCall methodCall) async { log.add(methodCall); - return 'foo'; + return 'avatars/large/image.jpg'; }); - ref = FirebaseStorage.instance - .ref() - .child('avatars') - .child('large') - .child('image.jpg'); + ref = storage.ref().child('avatars').child('large').child('image.jpg'); }); test('invokes correct method', () async { - await ref.getBucket(); + await ref.getPath(); expect(log, <Matcher>[ isMethodCall( - 'StorageReference#getBucket', + 'StorageReference#getPath', arguments: <String, dynamic>{ + 'app': 'testApp', + 'bucket': 'gs://fake-storage-bucket-url.com', 'path': 'avatars/large/image.jpg', }, ), @@ -247,80 +324,8 @@ }); test('returns correct result', () async { - expect(await ref.getBucket(), 'foo'); + expect(await ref.getPath(), 'avatars/large/image.jpg'); }); }); - - group('getName', () { - final List<MethodCall> log = <MethodCall>[]; - - StorageReference ref; - - setUp(() { - FirebaseStorage.channel - .setMockMethodCallHandler((MethodCall methodCall) async { - log.add(methodCall); - return 'image.jpg'; - }); - ref = FirebaseStorage.instance - .ref() - .child('avatars') - .child('large') - .child('image.jpg'); - }); - - test('invokes correct method', () async { - await ref.getName(); - - expect(log, <Matcher>[ - isMethodCall( - 'StorageReference#getName', - arguments: <String, dynamic>{ - 'path': 'avatars/large/image.jpg', - }, - ), - ]); - }); - - test('returns correct result', () async { - expect(await ref.getName(), 'image.jpg'); - }); - }); - }); - - group('getPath', () { - final List<MethodCall> log = <MethodCall>[]; - - StorageReference ref; - - setUp(() { - FirebaseStorage.channel - .setMockMethodCallHandler((MethodCall methodCall) async { - log.add(methodCall); - return 'avatars/large/image.jpg'; - }); - ref = FirebaseStorage.instance - .ref() - .child('avatars') - .child('large') - .child('image.jpg'); - }); - - test('invokes correct method', () async { - await ref.getPath(); - - expect(log, <Matcher>[ - isMethodCall( - 'StorageReference#getPath', - arguments: <String, dynamic>{ - 'path': 'avatars/large/image.jpg', - }, - ), - ]); - }); - - test('returns correct result', () async { - expect(await ref.getPath(), 'avatars/large/image.jpg'); - }); }); }