diff options
Diffstat (limited to 'spec/unit/chef_fs/file_pattern_spec.rb')
-rw-r--r-- | spec/unit/chef_fs/file_pattern_spec.rb | 526 |
1 files changed, 526 insertions, 0 deletions
diff --git a/spec/unit/chef_fs/file_pattern_spec.rb b/spec/unit/chef_fs/file_pattern_spec.rb new file mode 100644 index 0000000000..247ec01a77 --- /dev/null +++ b/spec/unit/chef_fs/file_pattern_spec.rb @@ -0,0 +1,526 @@ +# +# Author:: John Keiser (<jkeiser@opscode.com>) +# Copyright:: Copyright (c) 2012 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'spec_helper' +require 'chef/chef_fs/file_pattern' + +describe Chef::ChefFS::FilePattern do + def p(str) + Chef::ChefFS::FilePattern.new(str) + end + + # Different kinds of patterns + context 'with empty pattern ""' do + let(:pattern) { Chef::ChefFS::FilePattern.new('') } + it 'match?' do + pattern.match?('').should be_true + pattern.match?('/').should be_false + pattern.match?('a').should be_false + pattern.match?('a/b').should be_false + end + it 'exact_path' do + pattern.exact_path.should == '' + end + it 'could_match_children?' do + pattern.could_match_children?('').should be_false + pattern.could_match_children?('a/b').should be_false + end + end + + context 'with root pattern "/"' do + let(:pattern) { Chef::ChefFS::FilePattern.new('/') } + it 'match?' do + pattern.match?('/').should be_true + pattern.match?('').should be_false + pattern.match?('a').should be_false + pattern.match?('/a').should be_false + end + it 'exact_path' do + pattern.exact_path.should == '/' + end + it 'could_match_children?' do + pattern.could_match_children?('').should be_false + pattern.could_match_children?('/').should be_false + pattern.could_match_children?('a').should be_false + pattern.could_match_children?('a/b').should be_false + pattern.could_match_children?('/a').should be_false + end + end + + context 'with simple pattern "abc"' do + let(:pattern) { Chef::ChefFS::FilePattern.new('abc') } + it 'match?' do + pattern.match?('abc').should be_true + pattern.match?('a').should be_false + pattern.match?('abcd').should be_false + pattern.match?('/abc').should be_false + pattern.match?('').should be_false + pattern.match?('/').should be_false + end + it 'exact_path' do + pattern.exact_path.should == 'abc' + end + it 'could_match_children?' do + pattern.could_match_children?('').should be_false + pattern.could_match_children?('abc').should be_false + pattern.could_match_children?('/abc').should be_false + end + end + + context 'with simple pattern "/abc"' do + let(:pattern) { Chef::ChefFS::FilePattern.new('/abc') } + it 'match?' do + pattern.match?('/abc').should be_true + pattern.match?('abc').should be_false + pattern.match?('a').should be_false + pattern.match?('abcd').should be_false + pattern.match?('').should be_false + pattern.match?('/').should be_false + end + it 'exact_path' do + pattern.exact_path.should == '/abc' + end + it 'could_match_children?' do + pattern.could_match_children?('abc').should be_false + pattern.could_match_children?('/abc').should be_false + pattern.could_match_children?('/').should be_true + pattern.could_match_children?('').should be_false + end + it 'exact_child_name_under' do + pattern.exact_child_name_under('/').should == 'abc' + end + end + + context 'with simple pattern "abc/def/ghi"' do + let(:pattern) { Chef::ChefFS::FilePattern.new('abc/def/ghi') } + it 'match?' do + pattern.match?('abc/def/ghi').should be_true + pattern.match?('/abc/def/ghi').should be_false + pattern.match?('abc').should be_false + pattern.match?('abc/def').should be_false + end + it 'exact_path' do + pattern.exact_path.should == 'abc/def/ghi' + end + it 'could_match_children?' do + pattern.could_match_children?('abc').should be_true + pattern.could_match_children?('xyz').should be_false + pattern.could_match_children?('/abc').should be_false + pattern.could_match_children?('abc/def').should be_true + pattern.could_match_children?('abc/xyz').should be_false + pattern.could_match_children?('abc/def/ghi').should be_false + end + it 'exact_child_name_under' do + pattern.exact_child_name_under('abc').should == 'def' + pattern.exact_child_name_under('abc/def').should == 'ghi' + end + end + + context 'with simple pattern "/abc/def/ghi"' do + let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/def/ghi') } + it 'match?' do + pattern.match?('/abc/def/ghi').should be_true + pattern.match?('abc/def/ghi').should be_false + pattern.match?('/abc').should be_false + pattern.match?('/abc/def').should be_false + end + it 'exact_path' do + pattern.exact_path.should == '/abc/def/ghi' + end + it 'could_match_children?' do + pattern.could_match_children?('/abc').should be_true + pattern.could_match_children?('/xyz').should be_false + pattern.could_match_children?('abc').should be_false + pattern.could_match_children?('/abc/def').should be_true + pattern.could_match_children?('/abc/xyz').should be_false + pattern.could_match_children?('/abc/def/ghi').should be_false + end + it 'exact_child_name_under' do + pattern.exact_child_name_under('/').should == 'abc' + pattern.exact_child_name_under('/abc').should == 'def' + pattern.exact_child_name_under('/abc/def').should == 'ghi' + end + end + + context 'with simple pattern "a\*\b"' do + let(:pattern) { Chef::ChefFS::FilePattern.new('a\*\b') } + it 'match?' do + pattern.match?('a*b').should be_true + pattern.match?('ab').should be_false + pattern.match?('acb').should be_false + pattern.match?('ab').should be_false + end + it 'exact_path' do + pattern.exact_path.should == 'a*b' + end + it 'could_match_children?' do + pattern.could_match_children?('a/*b').should be_false + end + end + + context 'with star pattern "/abc/*/ghi"' do + let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/*/ghi') } + it 'match?' do + pattern.match?('/abc/def/ghi').should be_true + pattern.match?('/abc/ghi').should be_false + end + it 'exact_path' do + pattern.exact_path.should be_nil + end + it 'could_match_children?' do + pattern.could_match_children?('/abc').should be_true + pattern.could_match_children?('/xyz').should be_false + pattern.could_match_children?('abc').should be_false + pattern.could_match_children?('/abc/def').should be_true + pattern.could_match_children?('/abc/xyz').should be_true + pattern.could_match_children?('/abc/def/ghi').should be_false + end + it 'exact_child_name_under' do + pattern.exact_child_name_under('/').should == 'abc' + pattern.exact_child_name_under('/abc').should == nil + pattern.exact_child_name_under('/abc/def').should == 'ghi' + end + end + + context 'with star pattern "/abc/d*f/ghi"' do + let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/d*f/ghi') } + it 'match?' do + pattern.match?('/abc/def/ghi').should be_true + pattern.match?('/abc/dxf/ghi').should be_true + pattern.match?('/abc/df/ghi').should be_true + pattern.match?('/abc/dxyzf/ghi').should be_true + pattern.match?('/abc/d/ghi').should be_false + pattern.match?('/abc/f/ghi').should be_false + pattern.match?('/abc/ghi').should be_false + pattern.match?('/abc/xyz/ghi').should be_false + end + it 'exact_path' do + pattern.exact_path.should be_nil + end + it 'could_match_children?' do + pattern.could_match_children?('/abc').should be_true + pattern.could_match_children?('/xyz').should be_false + pattern.could_match_children?('abc').should be_false + pattern.could_match_children?('/abc/def').should be_true + pattern.could_match_children?('/abc/xyz').should be_false + pattern.could_match_children?('/abc/dxyzf').should be_true + pattern.could_match_children?('/abc/df').should be_true + pattern.could_match_children?('/abc/d').should be_false + pattern.could_match_children?('/abc/f').should be_false + pattern.could_match_children?('/abc/def/ghi').should be_false + end + it 'exact_child_name_under' do + pattern.exact_child_name_under('/').should == 'abc' + pattern.exact_child_name_under('/abc').should == nil + pattern.exact_child_name_under('/abc/def').should == 'ghi' + end + end + + context 'with star pattern "/abc/d??f/ghi"' do + let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/d??f/ghi') } + it 'match?' do + pattern.match?('/abc/deef/ghi').should be_true + pattern.match?('/abc/deeef/ghi').should be_false + pattern.match?('/abc/def/ghi').should be_false + pattern.match?('/abc/df/ghi').should be_false + pattern.match?('/abc/d/ghi').should be_false + pattern.match?('/abc/f/ghi').should be_false + pattern.match?('/abc/ghi').should be_false + end + it 'exact_path' do + pattern.exact_path.should be_nil + end + it 'could_match_children?' do + pattern.could_match_children?('/abc').should be_true + pattern.could_match_children?('/xyz').should be_false + pattern.could_match_children?('abc').should be_false + pattern.could_match_children?('/abc/deef').should be_true + pattern.could_match_children?('/abc/deeef').should be_false + pattern.could_match_children?('/abc/def').should be_false + pattern.could_match_children?('/abc/df').should be_false + pattern.could_match_children?('/abc/d').should be_false + pattern.could_match_children?('/abc/f').should be_false + pattern.could_match_children?('/abc/deef/ghi').should be_false + end + it 'exact_child_name_under' do + pattern.exact_child_name_under('/').should == 'abc' + pattern.exact_child_name_under('/abc').should == nil + pattern.exact_child_name_under('/abc/deef').should == 'ghi' + end + end + + context 'with star pattern "/abc/d[a-z][0-9]f/ghi"' do + let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/d[a-z][0-9]f/ghi') } + it 'match?' do + pattern.match?('/abc/de1f/ghi').should be_true + pattern.match?('/abc/deef/ghi').should be_false + pattern.match?('/abc/d11f/ghi').should be_false + pattern.match?('/abc/de11f/ghi').should be_false + pattern.match?('/abc/dee1f/ghi').should be_false + pattern.match?('/abc/df/ghi').should be_false + pattern.match?('/abc/d/ghi').should be_false + pattern.match?('/abc/f/ghi').should be_false + pattern.match?('/abc/ghi').should be_false + end + it 'exact_path' do + pattern.exact_path.should be_nil + end + it 'could_match_children?' do + pattern.could_match_children?('/abc').should be_true + pattern.could_match_children?('/xyz').should be_false + pattern.could_match_children?('abc').should be_false + pattern.could_match_children?('/abc/de1f').should be_true + pattern.could_match_children?('/abc/deef').should be_false + pattern.could_match_children?('/abc/d11f').should be_false + pattern.could_match_children?('/abc/de11f').should be_false + pattern.could_match_children?('/abc/dee1f').should be_false + pattern.could_match_children?('/abc/def').should be_false + pattern.could_match_children?('/abc/df').should be_false + pattern.could_match_children?('/abc/d').should be_false + pattern.could_match_children?('/abc/f').should be_false + pattern.could_match_children?('/abc/de1f/ghi').should be_false + end + it 'exact_child_name_under' do + pattern.exact_child_name_under('/').should == 'abc' + pattern.exact_child_name_under('/abc').should == nil + pattern.exact_child_name_under('/abc/de1f').should == 'ghi' + end + end + + context 'with star pattern "/abc/**/ghi"' do + let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/**/ghi') } + it 'match?' do + pattern.match?('/abc/def/ghi').should be_true + pattern.match?('/abc/d/e/f/ghi').should be_true + pattern.match?('/abc/ghi').should be_false + pattern.match?('/abcdef/d/ghi').should be_false + pattern.match?('/abc/d/defghi').should be_false + pattern.match?('/xyz').should be_false + end + it 'exact_path' do + pattern.exact_path.should be_nil + end + it 'could_match_children?' do + pattern.could_match_children?('/abc').should be_true + pattern.could_match_children?('/abc/d').should be_true + pattern.could_match_children?('/abc/d/e').should be_true + pattern.could_match_children?('/abc/d/e/f').should be_true + pattern.could_match_children?('/abc/def/ghi').should be_true + pattern.could_match_children?('abc').should be_false + pattern.could_match_children?('/xyz').should be_false + end + it 'exact_child_name_under' do + pattern.exact_child_name_under('/').should == 'abc' + pattern.exact_child_name_under('/abc').should == nil + pattern.exact_child_name_under('/abc/def').should == nil + end + end + + context 'with star pattern "/abc**/ghi"' do + let(:pattern) { Chef::ChefFS::FilePattern.new('/abc**/ghi') } + it 'match?' do + pattern.match?('/abc/def/ghi').should be_true + pattern.match?('/abc/d/e/f/ghi').should be_true + pattern.match?('/abc/ghi').should be_true + pattern.match?('/abcdef/ghi').should be_true + pattern.match?('/abc/defghi').should be_false + pattern.match?('/xyz').should be_false + end + it 'exact_path' do + pattern.exact_path.should be_nil + end + it 'could_match_children?' do + pattern.could_match_children?('/abc').should be_true + pattern.could_match_children?('/abcdef').should be_true + pattern.could_match_children?('/abc/d/e').should be_true + pattern.could_match_children?('/abc/d/e/f').should be_true + pattern.could_match_children?('/abc/def/ghi').should be_true + pattern.could_match_children?('abc').should be_false + end + it 'could_match_children? /abc** returns false for /xyz' do + pending 'Make could_match_children? more rigorous' do + # At the moment, we return false for this, but in the end it would be nice to return true: + pattern.could_match_children?('/xyz').should be_false + end + end + it 'exact_child_name_under' do + pattern.exact_child_name_under('/').should == nil + pattern.exact_child_name_under('/abc').should == nil + pattern.exact_child_name_under('/abc/def').should == nil + end + end + + context 'with star pattern "/abc/**ghi"' do + let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/**ghi') } + it 'match?' do + pattern.match?('/abc/def/ghi').should be_true + pattern.match?('/abc/def/ghi/ghi').should be_true + pattern.match?('/abc/def/ghi/jkl').should be_false + pattern.match?('/abc/d/e/f/ghi').should be_true + pattern.match?('/abc/ghi').should be_true + pattern.match?('/abcdef/ghi').should be_false + pattern.match?('/abc/defghi').should be_true + pattern.match?('/xyz').should be_false + end + it 'exact_path' do + pattern.exact_path.should be_nil + end + it 'could_match_children?' do + pattern.could_match_children?('/abc').should be_true + pattern.could_match_children?('/abcdef').should be_false + pattern.could_match_children?('/abc/d/e').should be_true + pattern.could_match_children?('/abc/d/e/f').should be_true + pattern.could_match_children?('/abc/def/ghi').should be_true + pattern.could_match_children?('abc').should be_false + pattern.could_match_children?('/xyz').should be_false + end + it 'exact_child_name_under' do + pattern.exact_child_name_under('/').should == 'abc' + pattern.exact_child_name_under('/abc').should == nil + pattern.exact_child_name_under('/abc/def').should == nil + end + end + + context 'with star pattern "a**b**c"' do + let(:pattern) { Chef::ChefFS::FilePattern.new('a**b**c') } + it 'match?' do + pattern.match?('axybzwc').should be_true + pattern.match?('abc').should be_true + pattern.match?('axyzwc').should be_false + pattern.match?('ac').should be_false + pattern.match?('a/x/y/b/z/w/c').should be_true + end + it 'exact_path' do + pattern.exact_path.should be_nil + end + end + + context 'normalization tests' do + it 'handles trailing slashes' do + p('abc/').normalized_pattern.should == 'abc' + p('abc/').exact_path.should == 'abc' + p('abc/').match?('abc').should be_true + p('//').normalized_pattern.should == '/' + p('//').exact_path.should == '/' + p('//').match?('/').should be_true + p('/./').normalized_pattern.should == '/' + p('/./').exact_path.should == '/' + p('/./').match?('/').should be_true + end + it 'handles multiple slashes' do + p('abc//def').normalized_pattern.should == 'abc/def' + p('abc//def').exact_path.should == 'abc/def' + p('abc//def').match?('abc/def').should be_true + p('abc//').normalized_pattern.should == 'abc' + p('abc//').exact_path.should == 'abc' + p('abc//').match?('abc').should be_true + end + it 'handles dot' do + p('abc/./def').normalized_pattern.should == 'abc/def' + p('abc/./def').exact_path.should == 'abc/def' + p('abc/./def').match?('abc/def').should be_true + p('./abc/def').normalized_pattern.should == 'abc/def' + p('./abc/def').exact_path.should == 'abc/def' + p('./abc/def').match?('abc/def').should be_true + p('/.').normalized_pattern.should == '/' + p('/.').exact_path.should == '/' + p('/.').match?('/').should be_true + end + it 'handles dot by itself', :pending => "decide what to do with dot by itself" do + p('.').normalized_pattern.should == '.' + p('.').exact_path.should == '.' + p('.').match?('.').should be_true + p('./').normalized_pattern.should == '.' + p('./').exact_path.should == '.' + p('./').match?('.').should be_true + end + it 'handles dotdot' do + p('abc/../def').normalized_pattern.should == 'def' + p('abc/../def').exact_path.should == 'def' + p('abc/../def').match?('def').should be_true + p('abc/def/../..').normalized_pattern.should == '' + p('abc/def/../..').exact_path.should == '' + p('abc/def/../..').match?('').should be_true + p('/*/../def').normalized_pattern.should == '/def' + p('/*/../def').exact_path.should == '/def' + p('/*/../def').match?('/def').should be_true + p('/*/*/../def').normalized_pattern.should == '/*/def' + p('/*/*/../def').exact_path.should be_nil + p('/*/*/../def').match?('/abc/def').should be_true + p('/abc/def/../..').normalized_pattern.should == '/' + p('/abc/def/../..').exact_path.should == '/' + p('/abc/def/../..').match?('/').should be_true + p('abc/../../def').normalized_pattern.should == '../def' + p('abc/../../def').exact_path.should == '../def' + p('abc/../../def').match?('../def').should be_true + end + it 'handles dotdot with double star' do + p('abc**/def/../ghi').exact_path.should be_nil + p('abc**/def/../ghi').match?('abc/ghi').should be_true + p('abc**/def/../ghi').match?('abc/x/y/z/ghi').should be_true + p('abc**/def/../ghi').match?('ghi').should be_false + end + it 'raises error on dotdot with overlapping double star' do + lambda { Chef::ChefFS::FilePattern.new('abc/**/../def').exact_path }.should raise_error(ArgumentError) + lambda { Chef::ChefFS::FilePattern.new('abc/**/abc/../../def').exact_path }.should raise_error(ArgumentError) + end + it 'handles leading dotdot' do + p('../abc/def').exact_path.should == '../abc/def' + p('../abc/def').match?('../abc/def').should be_true + p('/../abc/def').exact_path.should == '/abc/def' + p('/../abc/def').match?('/abc/def').should be_true + p('..').exact_path.should == '..' + p('..').match?('..').should be_true + p('/..').exact_path.should == '/' + p('/..').match?('/').should be_true + end + end + + + # match? + # - single element matches (empty, fixed, ?, *, characters, escapes) + # - nested matches + # - absolute matches + # - trailing slashes + # - ** + + # exact_path + # - empty + # - single element and nested matches, with escapes + # - absolute and relative + # - ?, *, characters, ** + + # could_match_children? + # + # + # + # + context 'with pattern "abc"' do + end + + context 'with pattern "/abc"' do + end + + context 'with pattern "abc/def/ghi"' do + end + + context 'with pattern "/abc/def/ghi"' do + end + + # Exercise the different methods to their maximum +end |