15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <list>
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <utility>
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/scoped_temp_dir.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/file_util_icu.h"
129ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
135e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/directory_lister.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "testing/platform_test.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ListerDelegate : public DirectoryLister::DirectoryListerDelegate {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ListerDelegate(bool recursive,
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 bool quit_loop_after_each_file)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : error_(-1),
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        recursive_(recursive),
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        quit_loop_after_each_file_(quit_loop_after_each_file) {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnListFile(
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const DirectoryLister::DirectoryListerData& data) OVERRIDE {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_list_.push_back(data.info);
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    paths_.push_back(data.path);
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (quit_loop_after_each_file_)
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::MessageLoop::current()->Quit();
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnListDone(int error) OVERRIDE {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_ = error;
4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->Quit();
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (recursive_)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CheckRecursiveSort();
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CheckSort();
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CheckRecursiveSort() {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check that we got files in the right order.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!file_list_.empty()) {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t previous = 0, current = 1;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           current < file_list_.size();
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           previous++, current++) {
536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        EXPECT_TRUE(base::i18n::LocaleAwareCompareFilenames(
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            paths_[previous], paths_[current]));
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CheckSort() {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check that we got files in the right order.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!file_list_.empty()) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t previous = 0, current = 1;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           current < file_list_.size();
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           previous++, current++) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Directories should come before files.
66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        if (file_list_[previous].IsDirectory() &&
67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            !file_list_[current].IsDirectory()) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          continue;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        EXPECT_NE(FILE_PATH_LITERAL(".."),
71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  file_list_[current].GetName().BaseName().value());
72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        EXPECT_EQ(file_list_[previous].IsDirectory(),
73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  file_list_[current].IsDirectory());
746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        EXPECT_TRUE(base::i18n::LocaleAwareCompareFilenames(
75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            file_list_[previous].GetName(),
76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            file_list_[current].GetName()));
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int error() const { return error_; }
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num_files() const { return file_list_.size(); }
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int error_;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool recursive_;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool quit_loop_after_each_file_;
89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::vector<base::FileEnumerator::FileInfo> file_list_;
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<base::FilePath> paths_;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class DirectoryListerTest : public PlatformTest {
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public:
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual void SetUp() OVERRIDE {
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const int kMaxDepth = 3;
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const int kBranchingFactor = 4;
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const int kFilesPerDirectory = 5;
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Randomly create a directory structure of depth 3 in a temporary root
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // directory.
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::list<std::pair<base::FilePath, int> > directories;
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ASSERT_TRUE(temp_root_dir_.CreateUniqueTempDir());
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    directories.push_back(std::make_pair(temp_root_dir_.path(), 0));
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    while (!directories.empty()) {
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      std::pair<base::FilePath, int> dir_data = directories.front();
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      directories.pop_front();
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      for (int i = 0; i < kFilesPerDirectory; i++) {
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        std::string file_name = base::StringPrintf("file_id_%d", i);
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::FilePath file_path = dir_data.first.AppendASCII(file_name);
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::File file(file_path,
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        base::File::FLAG_CREATE | base::File::FLAG_WRITE);
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ASSERT_TRUE(file.IsValid());
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (dir_data.second < kMaxDepth - 1) {
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        for (int i = 0; i < kBranchingFactor; i++) {
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          std::string dir_name = base::StringPrintf("child_dir_%d", i);
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          base::FilePath dir_path = dir_data.first.AppendASCII(dir_name);
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          ASSERT_TRUE(base::CreateDirectory(dir_path));
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          directories.push_back(std::make_pair(dir_path, dir_data.second + 1));
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    PlatformTest::SetUp();
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::FilePath& root_path() const {
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return temp_root_dir_.path();
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private:
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ScopedTempDir temp_root_dir_;
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TEST_F(DirectoryListerTest, BigDirTest) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ListerDelegate delegate(false, false);
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DirectoryLister lister(root_path(), &delegate);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  lister.Start();
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->Run();
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(OK, delegate.error());
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TEST_F(DirectoryListerTest, BigDirRecursiveTest) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ListerDelegate delegate(true, false);
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DirectoryLister lister(root_path(), true, DirectoryLister::FULL_PATH,
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         &delegate);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  lister.Start();
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->Run();
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(OK, delegate.error());
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TEST_F(DirectoryListerTest, CancelTest) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ListerDelegate delegate(false, true);
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DirectoryLister lister(root_path(), &delegate);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  lister.Start();
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->Run();
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num_files = delegate.num_files();
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  lister.Cancel();
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->RunUntilIdle();
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(num_files, delegate.num_files());
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TEST_F(DirectoryListerTest, EmptyDirTest) {
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ScopedTempDir tempDir;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(tempDir.CreateUniqueTempDir());
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool kRecursive = false;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool kQuitLoopAfterEachFile = false;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ListerDelegate delegate(kRecursive, kQuitLoopAfterEachFile);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DirectoryLister lister(tempDir.path(), &delegate);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  lister.Start();
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->Run();
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Contains only the parent directory ("..")
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, delegate.num_files());
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(OK, delegate.error());
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
191