From 37b2c5dd5521f25a7195e82538a0ffc528c3ec6d Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon <grzesiek.bizon@gmail.com>
Date: Mon, 21 Dec 2015 12:08:04 +0100
Subject: [PATCH] Add support for root path for `StringPath`

---
 lib/gitlab/string_path.rb           | 26 ++++++++++++++++++--------
 spec/lib/gitlab/string_path_spec.rb | 24 +++++++++++++++++++++++-
 2 files changed, 41 insertions(+), 9 deletions(-)

diff --git a/lib/gitlab/string_path.rb b/lib/gitlab/string_path.rb
index a2dc63db2f..d165829132 100644
--- a/lib/gitlab/string_path.rb
+++ b/lib/gitlab/string_path.rb
@@ -1,6 +1,6 @@
 module Gitlab
   ## 
-  # Class that represents a path to a file or directory
+  # Class that represents a simplified path to a file or directory
   #
   # This is IO-operations safe class, that does similar job to 
   # Ruby's Pathname but without the risk of accessing filesystem.
@@ -10,8 +10,9 @@ module Gitlab
     attr_reader :path, :universe
 
     def initialize(path, universe)
-      @path = path
-      @universe = universe
+      @path = prepare(path)
+      @universe = universe.map { |entry| prepare(entry) }
+      @universe.unshift('./') unless @universe.include?('./')
     end
 
     def to_s
@@ -43,6 +44,15 @@ module Gitlab
       new(@path.sub(basename, ''))
     end
 
+    def basename
+      name = @path.split(::File::SEPARATOR).last
+      directory? ? name + ::File::SEPARATOR : name
+    end
+
+    def has_descendants?
+      descendants.any?
+    end
+
     def descendants
       return [] unless directory?
       children = @universe.select { |entry| entry =~ /^#{@path}.+/ }
@@ -63,11 +73,6 @@ module Gitlab
       children.select { |child| child.file? }
     end
 
-    def basename
-      name = @path.split(::File::SEPARATOR).last
-      directory? ? name + ::File::SEPARATOR : name
-    end
-
     def ==(other)
       @path == other.path && @universe == other.universe
     end
@@ -77,5 +82,10 @@ module Gitlab
     def new(path)
       self.class.new(path, @universe)
     end
+
+    def prepare(path)
+      return path if path =~ %r{^(/|\.|\.\.)}
+      path.dup.prepend('./')
+    end
   end
 end
diff --git a/spec/lib/gitlab/string_path_spec.rb b/spec/lib/gitlab/string_path_spec.rb
index 7818e34072..7ee69c7d3c 100644
--- a/spec/lib/gitlab/string_path_spec.rb
+++ b/spec/lib/gitlab/string_path_spec.rb
@@ -11,6 +11,7 @@ describe Gitlab::StringPath do
      'path/second_dir',
      'path/second_dir/dir_3/file_2',
      'path/second_dir/dir_3/file_3',
+     'another_directory/',
      'another_file',
      '/file/with/absolute_path']
   end
@@ -30,6 +31,7 @@ describe Gitlab::StringPath do
     it { is_expected.to_not be_relative }
     it { is_expected.to be_file }
     it { is_expected.to_not have_parent }
+    it { is_expected.to_not have_descendants }
 
     describe '#basename' do
       subject { |example| path(example).basename }
@@ -43,7 +45,7 @@ describe Gitlab::StringPath do
 
     it { is_expected.to be_directory }
     it { is_expected.to be_relative }
-    it { is_expected.to_not have_parent }
+    it { is_expected.to have_parent }
   end
 
   describe 'path/dir_1/', path: 'path/dir_1/' do
@@ -100,4 +102,24 @@ describe Gitlab::StringPath do
       it { is_expected.to contain_exactly string_path('path/dir_1/subdir/') }
     end
   end
+
+  describe './', path: './' do
+    subject { |example| path(example) }
+
+    it { is_expected.to_not have_parent }
+    it { is_expected.to have_descendants }
+
+    describe '#descendants' do
+      subject { |example| path(example).descendants }
+
+      it { expect(subject.count).to eq universe.count - 1 }
+      it { is_expected.to_not include string_path('./') }
+    end
+
+    describe '#children' do
+      subject { |example| path(example).children }
+
+      it { expect(subject.count).to eq 3 }
+    end
+  end
 end
-- 
2.30.9