Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / components / storage_monitor / image_capture_device_manager_unittest.mm
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import <Foundation/Foundation.h>
6 #import <ImageCaptureCore/ImageCaptureCore.h>
7
8 #include "base/files/file_path.h"
9 #include "base/files/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/mac/foundation_util.h"
12 #include "base/mac/sdk_forward_declarations.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/run_loop.h"
15 #include "components/storage_monitor/image_capture_device.h"
16 #include "components/storage_monitor/image_capture_device_manager.h"
17 #include "components/storage_monitor/test_storage_monitor.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/test/test_browser_thread_bundle.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 namespace {
23
24 const char kDeviceId[] = "id";
25 const char kTestFileContents[] = "test";
26
27 }  // namespace
28
29 // Private ICCameraDevice method needed to properly initialize the object.
30 @interface NSObject (PrivateAPIICCameraDevice)
31 - (id)initWithDictionary:(id)properties;
32 @end
33
34 @interface MockICCameraDevice : ICCameraDevice {
35  @private
36   base::scoped_nsobject<NSMutableArray> allMediaFiles_;
37 }
38
39 - (void)addMediaFile:(ICCameraFile*)file;
40
41 @end
42
43 @implementation MockICCameraDevice
44
45 - (id)init {
46   if ((self = [super initWithDictionary:[NSDictionary dictionary]])) {
47   }
48   return self;
49 }
50
51 - (NSString*)mountPoint {
52   return @"mountPoint";
53 }
54
55 - (NSString*)name {
56   return @"name";
57 }
58
59 - (NSString*)UUIDString {
60   return base::SysUTF8ToNSString(kDeviceId);
61 }
62
63 - (ICDeviceType)type {
64   return ICDeviceTypeCamera;
65 }
66
67 - (void)requestOpenSession {
68 }
69
70 - (void)requestCloseSession {
71 }
72
73 - (NSArray*)mediaFiles {
74   return allMediaFiles_;
75 }
76
77 - (void)addMediaFile:(ICCameraFile*)file {
78   if (!allMediaFiles_.get())
79     allMediaFiles_.reset([[NSMutableArray alloc] init]);
80   [allMediaFiles_ addObject:file];
81 }
82
83 // This method does approximately what the internal ImageCapture platform
84 // library is observed to do: take the download save-as filename and mangle
85 // it to attach an extension, then return that new filename to the caller
86 // in the options.
87 - (void)requestDownloadFile:(ICCameraFile*)file
88                     options:(NSDictionary*)options
89            downloadDelegate:(id<ICCameraDeviceDownloadDelegate>)downloadDelegate
90         didDownloadSelector:(SEL)selector
91                 contextInfo:(void*)contextInfo {
92   base::FilePath saveDir(base::SysNSStringToUTF8(
93       [[options objectForKey:ICDownloadsDirectoryURL] path]));
94   std::string saveAsFilename =
95       base::SysNSStringToUTF8([options objectForKey:ICSaveAsFilename]);
96   // It appears that the ImageCapture library adds an extension to the requested
97   // filename. Do that here to require a rename.
98   saveAsFilename += ".jpg";
99   base::FilePath toBeSaved = saveDir.Append(saveAsFilename);
100   ASSERT_EQ(static_cast<int>(strlen(kTestFileContents)),
101             base::WriteFile(toBeSaved, kTestFileContents,
102                             strlen(kTestFileContents)));
103
104   NSMutableDictionary* returnOptions =
105       [NSMutableDictionary dictionaryWithDictionary:options];
106   [returnOptions setObject:base::SysUTF8ToNSString(saveAsFilename)
107                     forKey:ICSavedFilename];
108
109   [static_cast<NSObject<ICCameraDeviceDownloadDelegate>*>(downloadDelegate)
110    didDownloadFile:file
111              error:nil
112            options:returnOptions
113        contextInfo:contextInfo];
114 }
115
116 @end
117
118 @interface MockICCameraFolder : ICCameraFolder {
119  @private
120   base::scoped_nsobject<NSString> name_;
121 }
122
123 - (id)initWithName:(NSString*)name;
124
125 @end
126
127 @implementation MockICCameraFolder
128
129 - (id)initWithName:(NSString*)name {
130   if ((self = [super init])) {
131     name_.reset([name retain]);
132   }
133   return self;
134 }
135
136 - (NSString*)name {
137   return name_;
138 }
139
140 - (ICCameraFolder*)parentFolder {
141   return nil;
142 }
143
144 @end
145
146 @interface MockICCameraFile : ICCameraFile {
147  @private
148   base::scoped_nsobject<NSString> name_;
149   base::scoped_nsobject<NSDate> date_;
150   base::scoped_nsobject<MockICCameraFolder> parent_;
151 }
152
153 - (id)init:(NSString*)name;
154 - (void)setParent:(NSString*)parent;
155
156 @end
157
158 @implementation MockICCameraFile
159
160 - (id)init:(NSString*)name {
161   if ((self = [super init])) {
162     name_.reset([name retain]);
163     date_.reset([[NSDate dateWithNaturalLanguageString:@"12/12/12"] retain]);
164   }
165   return self;
166 }
167
168 - (void)setParent:(NSString*)parent {
169   parent_.reset([[MockICCameraFolder alloc] initWithName:parent]);
170 }
171
172 - (ICCameraFolder*)parentFolder {
173   return parent_.get();
174 }
175
176 - (NSString*)name {
177   return name_;
178 }
179
180 - (NSString*)UTI {
181   return base::mac::CFToNSCast(kUTTypeImage);
182 }
183
184 - (NSDate*)modificationDate {
185   return date_.get();
186 }
187
188 - (NSDate*)creationDate {
189   return date_.get();
190 }
191
192 - (off_t)fileSize {
193   return 1000;
194 }
195
196 @end
197
198 namespace storage_monitor {
199
200 class TestCameraListener
201     : public ImageCaptureDeviceListener,
202       public base::SupportsWeakPtr<TestCameraListener> {
203  public:
204   TestCameraListener()
205       : completed_(false),
206         removed_(false),
207         last_error_(base::File::FILE_ERROR_INVALID_URL) {}
208   ~TestCameraListener() override {}
209
210   void ItemAdded(const std::string& name,
211                  const base::File::Info& info) override {
212     items_.push_back(name);
213   }
214
215   void NoMoreItems() override { completed_ = true; }
216
217   void DownloadedFile(const std::string& name,
218                       base::File::Error error) override {
219     EXPECT_TRUE(content::BrowserThread::CurrentlyOn(
220         content::BrowserThread::UI));
221     downloads_.push_back(name);
222     last_error_ = error;
223   }
224
225   void DeviceRemoved() override { removed_ = true; }
226
227   std::vector<std::string> items() const { return items_; }
228   std::vector<std::string> downloads() const { return downloads_; }
229   bool completed() const { return completed_; }
230   bool removed() const { return removed_; }
231   base::File::Error last_error() const { return last_error_; }
232
233  private:
234   std::vector<std::string> items_;
235   std::vector<std::string> downloads_;
236   bool completed_;
237   bool removed_;
238   base::File::Error last_error_;
239 };
240
241 class ImageCaptureDeviceManagerTest : public testing::Test {
242  public:
243   virtual void SetUp() override {
244     monitor_ = TestStorageMonitor::CreateAndInstall();
245   }
246
247   virtual void TearDown() override {
248     TestStorageMonitor::Destroy();
249   }
250
251   MockICCameraDevice* AttachDevice(ImageCaptureDeviceManager* manager) {
252     // Ownership will be passed to the device browser delegate.
253     base::scoped_nsobject<MockICCameraDevice> device(
254         [[MockICCameraDevice alloc] init]);
255     id<ICDeviceBrowserDelegate> delegate = manager->device_browser();
256     [delegate deviceBrowser:nil didAddDevice:device moreComing:NO];
257     return device.autorelease();
258   }
259
260   void DetachDevice(ImageCaptureDeviceManager* manager,
261                     ICCameraDevice* device) {
262     id<ICDeviceBrowserDelegate> delegate = manager->device_browser();
263     [delegate deviceBrowser:nil didRemoveDevice:device moreGoing:NO];
264   }
265
266  protected:
267   content::TestBrowserThreadBundle thread_bundle_;
268   TestStorageMonitor* monitor_;
269   TestCameraListener listener_;
270 };
271
272 TEST_F(ImageCaptureDeviceManagerTest, TestAttachDetach) {
273   ImageCaptureDeviceManager manager;
274   manager.SetNotifications(monitor_->receiver());
275   ICCameraDevice* device = AttachDevice(&manager);
276   std::vector<StorageInfo> devices = monitor_->GetAllAvailableStorages();
277
278   ASSERT_EQ(1U, devices.size());
279   EXPECT_EQ(std::string("ic:") + kDeviceId, devices[0].device_id());
280
281   DetachDevice(&manager, device);
282   devices = monitor_->GetAllAvailableStorages();
283   ASSERT_EQ(0U, devices.size());
284 };
285
286 TEST_F(ImageCaptureDeviceManagerTest, OpenCamera) {
287   ImageCaptureDeviceManager manager;
288   manager.SetNotifications(monitor_->receiver());
289   ICCameraDevice* device = AttachDevice(&manager);
290
291   EXPECT_FALSE(ImageCaptureDeviceManager::deviceForUUID(
292       "nonexistent"));
293
294   base::scoped_nsobject<ImageCaptureDevice> camera(
295       [ImageCaptureDeviceManager::deviceForUUID(kDeviceId) retain]);
296
297   [camera setListener:listener_.AsWeakPtr()];
298   [camera open];
299
300   base::scoped_nsobject<MockICCameraFile> picture1(
301       [[MockICCameraFile alloc] init:@"pic1"]);
302   [camera cameraDevice:nil didAddItem:picture1];
303   base::scoped_nsobject<MockICCameraFile> picture2(
304       [[MockICCameraFile alloc] init:@"pic2"]);
305   [camera cameraDevice:nil didAddItem:picture2];
306   ASSERT_EQ(2U, listener_.items().size());
307   EXPECT_EQ("pic1", listener_.items()[0]);
308   EXPECT_EQ("pic2", listener_.items()[1]);
309   EXPECT_FALSE(listener_.completed());
310
311   [camera deviceDidBecomeReadyWithCompleteContentCatalog:nil];
312
313   ASSERT_EQ(2U, listener_.items().size());
314   EXPECT_TRUE(listener_.completed());
315
316   [camera close];
317   DetachDevice(&manager, device);
318   EXPECT_FALSE(ImageCaptureDeviceManager::deviceForUUID(kDeviceId));
319 }
320
321 TEST_F(ImageCaptureDeviceManagerTest, RemoveCamera) {
322   ImageCaptureDeviceManager manager;
323   manager.SetNotifications(monitor_->receiver());
324   ICCameraDevice* device = AttachDevice(&manager);
325
326   base::scoped_nsobject<ImageCaptureDevice> camera(
327       [ImageCaptureDeviceManager::deviceForUUID(kDeviceId) retain]);
328
329   [camera setListener:listener_.AsWeakPtr()];
330   [camera open];
331
332   [camera didRemoveDevice:device];
333   EXPECT_TRUE(listener_.removed());
334 }
335
336 TEST_F(ImageCaptureDeviceManagerTest, DownloadFile) {
337   ImageCaptureDeviceManager manager;
338   manager.SetNotifications(monitor_->receiver());
339   MockICCameraDevice* device = AttachDevice(&manager);
340
341   base::scoped_nsobject<ImageCaptureDevice> camera(
342       [ImageCaptureDeviceManager::deviceForUUID(kDeviceId) retain]);
343
344   [camera setListener:listener_.AsWeakPtr()];
345   [camera open];
346
347   std::string kTestFileName("pic1");
348
349   base::scoped_nsobject<MockICCameraFile> picture1(
350       [[MockICCameraFile alloc] init:base::SysUTF8ToNSString(kTestFileName)]);
351   [device addMediaFile:picture1];
352   [camera cameraDevice:nil didAddItem:picture1];
353
354   base::ScopedTempDir temp_dir;
355   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
356
357   EXPECT_EQ(0U, listener_.downloads().size());
358
359   // Test that a nonexistent file we ask to be downloaded will
360   // return us a not-found error.
361   base::FilePath temp_file = temp_dir.path().Append("tempfile");
362   [camera downloadFile:std::string("nonexistent") localPath:temp_file];
363   base::RunLoop().RunUntilIdle();
364   ASSERT_EQ(1U, listener_.downloads().size());
365   EXPECT_EQ("nonexistent", listener_.downloads()[0]);
366   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, listener_.last_error());
367
368   // Test that an existing file we ask to be downloaded will end up in
369   // the location we specify. The mock system will copy testing file
370   // contents to a separate filename, mimicking the ImageCaptureCore
371   // library behavior. Our code then renames the file onto the requested
372   // destination.
373   [camera downloadFile:kTestFileName localPath:temp_file];
374   base::RunLoop().RunUntilIdle();
375
376   ASSERT_EQ(2U, listener_.downloads().size());
377   EXPECT_EQ(kTestFileName, listener_.downloads()[1]);
378   ASSERT_EQ(base::File::FILE_OK, listener_.last_error());
379   char file_contents[5];
380   ASSERT_EQ(4, base::ReadFile(temp_file, file_contents,
381                               strlen(kTestFileContents)));
382   EXPECT_EQ(kTestFileContents,
383             std::string(file_contents, strlen(kTestFileContents)));
384
385   [camera didRemoveDevice:device];
386 }
387
388 TEST_F(ImageCaptureDeviceManagerTest, TestSubdirectories) {
389   ImageCaptureDeviceManager manager;
390   manager.SetNotifications(monitor_->receiver());
391   MockICCameraDevice* device = AttachDevice(&manager);
392
393   base::scoped_nsobject<ImageCaptureDevice> camera(
394       [ImageCaptureDeviceManager::deviceForUUID(kDeviceId) retain]);
395
396   [camera setListener:listener_.AsWeakPtr()];
397   [camera open];
398
399   std::string kTestFileName("pic1");
400   base::scoped_nsobject<MockICCameraFile> picture1(
401       [[MockICCameraFile alloc] init:base::SysUTF8ToNSString(kTestFileName)]);
402   [picture1 setParent:base::SysUTF8ToNSString("dir")];
403   [device addMediaFile:picture1];
404   [camera cameraDevice:nil didAddItem:picture1];
405
406   base::ScopedTempDir temp_dir;
407   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
408   base::FilePath temp_file = temp_dir.path().Append("tempfile");
409
410   [camera downloadFile:("dir/" + kTestFileName) localPath:temp_file];
411   base::RunLoop().RunUntilIdle();
412
413   char file_contents[5];
414   ASSERT_EQ(4, base::ReadFile(temp_file, file_contents,
415                               strlen(kTestFileContents)));
416   EXPECT_EQ(kTestFileContents,
417             std::string(file_contents, strlen(kTestFileContents)));
418
419   [camera didRemoveDevice:device];
420 }
421
422 }  // namespace storage_monitor