From 95c86560c0ee3d82c4c789372d0a28966af16859 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Fri, 17 Jul 2009 04:18:43 +0800 Subject: [PATCH 01/12] Added verify.rb to find gaps in FakeFS Signed-off-by: Chris Wanstrath --- test/verify.rb | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 test/verify.rb diff --git a/test/verify.rb b/test/verify.rb new file mode 100644 index 0000000..9fa1ff7 --- /dev/null +++ b/test/verify.rb @@ -0,0 +1,27 @@ +# Figure out what's missing from fakefs +# +# USAGE +# +# $ ruby test/verify.rb | grep "not implemented" +require 'fakefs' +require 'test/unit' + +class FakeFSVerifierTest < Test::Unit::TestCase + (RealFile.methods - Class.new.methods).each do |name| + define_method("test #{name} class method") do + assert File.respond_to?(name), "File.#{name} not implemented" + end + end + + (RealFile.instance_methods - Enumerable.instance_methods).each do |name| + define_method("test #{name} instance method") do + assert File.instance_methods.include?(name), "File##{name} not implemented" + end + end + + (RealFileUtils.methods - Class.new.methods).each do |name| + define_method("test #{name} module method") do + assert FileUtils.respond_to?(name), "FileUtils.#{name} not implemented" + end + end +end From c93867a2fd9d1cc7dd09fc3bbe18a38e5031cb77 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Fri, 17 Jul 2009 04:19:03 +0800 Subject: [PATCH 02/12] Implemented File#<< and File#close Signed-off-by: Chris Wanstrath --- lib/fakefs.rb | 9 +++++++++ test/fakefs_test.rb | 20 +++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/fakefs.rb b/lib/fakefs.rb index 52ab82b..f1ffebd 100644 --- a/lib/fakefs.rb +++ b/lib/fakefs.rb @@ -193,9 +193,15 @@ module FakeFS @path = path @mode = mode @file = FileSystem.find(path) + @open = true + end + + def close + @open = false end def read + raise IOError.new('closed stream') unless @open @file.content end @@ -208,6 +214,8 @@ module FakeFS end def write(content) + raise IOError.new('closed stream') unless @open + if !File.exists?(@path) @file = FileSystem.add(path, MockFile.new) end @@ -215,6 +223,7 @@ module FakeFS @file.content += content end alias_method :print, :write + alias_method :<<, :write def flush; self; end end diff --git a/test/fakefs_test.rb b/test/fakefs_test.rb index dc20127..bc4c8f3 100644 --- a/test/fakefs_test.rb +++ b/test/fakefs_test.rb @@ -94,6 +94,14 @@ class FakeFSTest < Test::Unit::TestCase assert_equal "Yatta!", File.read(path) end + def test_can_write_to_files + path = '/path/to/file.txt' + File.open(path, 'w') do |f| + f << 'Yada Yada' + end + assert_equal 'Yada Yada', File.read(path) + end + def test_can_read_with_File_readlines path = '/path/to/file.txt' File.open(path, 'w') do |f| @@ -104,6 +112,16 @@ class FakeFSTest < Test::Unit::TestCase assert_equal ["Yatta!", "woot"], File.readlines(path) end + def test_File_close_disallows_further_access + path = '/path/to/file.txt' + file = File.open(path, 'w') + file.write 'Yada' + file.close + assert_raise IOError do + file.read + end + end + def test_can_read_from_file_objects path = '/path/to/file.txt' File.open(path, 'w') do |f| @@ -445,7 +463,7 @@ class FakeFSTest < Test::Unit::TestCase FileUtils.ln_s 'subdir', 'new' assert_equal 'works', File.open('new/nother'){|f| f.read } end - + def test_files_can_be_touched FileUtils.touch('touched_file') assert File.exists?('touched_file') From 04a6a7a5276f2bd7d925811086270d5b12896c80 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Sun, 19 Jul 2009 14:16:21 -0700 Subject: [PATCH 03/12] when copying or moving files, ensure the new parent gets set correctly --- lib/fakefs.rb | 24 +++++++++++++++++++----- test/fakefs_test.rb | 11 +++++++++-- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/lib/fakefs.rb b/lib/fakefs.rb index 52ab82b..00a16c9 100644 --- a/lib/fakefs.rb +++ b/lib/fakefs.rb @@ -38,10 +38,10 @@ module FakeFS end if dst_file and File.directory?(dst_file) - FileSystem.add(File.join(dest, src), src_file.entry.clone) + FileSystem.add(File.join(dest, src), src_file.entry.clone(dest)) else FileSystem.delete(dest) - FileSystem.add(dest, src_file.entry.clone) + FileSystem.add(dest, src_file.entry.clone(dest)) end end @@ -66,16 +66,16 @@ module FakeFS if src[-2..-1] == '/.' dir.values.each{|f| new_dir[f.name] = f } else - new_dir[dir.name] = dir.entry.clone + new_dir[dir.name] = dir.entry.clone(new_dir) end else - FileSystem.add(dest, dir.entry.clone) + FileSystem.add(dest, dir.entry.clone(dest)) end end def mv(src, dest) if target = FileSystem.find(src) - FileSystem.add(dest, target.entry.clone) + FileSystem.add(dest, target.entry.clone(dest)) FileSystem.delete(src) else raise Errno::ENOENT, src @@ -350,6 +350,12 @@ module FakeFS @content = '' end + def clone(parent) + clone = super() + clone.parent = parent + clone + end + def entry self end @@ -371,6 +377,14 @@ module FakeFS self end + def clone(parent) + clone = super() + clone.each do |key, value| + value.parent = parent + end + clone + end + def to_s if parent && parent.to_s != '.' File.join(parent.to_s, name) diff --git a/test/fakefs_test.rb b/test/fakefs_test.rb index dc20127..17e36d5 100644 --- a/test/fakefs_test.rb +++ b/test/fakefs_test.rb @@ -175,8 +175,15 @@ class FakeFSTest < Test::Unit::TestCase FileUtils.mkdir_p '/path' File.open('/path/foo', 'w'){|f| f.write 'foo' } File.open('/path/foobar', 'w'){|f| f.write 'foo' } + + FileUtils.mkdir_p '/path/bar' + File.open('/path/bar/baz', 'w'){|f| f.write 'foo' } + assert_equal ['/path'], Dir['/path'] - assert_equal ['/path/foo', '/path/foobar'], Dir['/path/*'] + assert_equal ['/path/bar', '/path/foo', '/path/foobar'], Dir['/path/*'] + + assert_equal ['/path/bar/baz'], Dir['/path/bar/*'] + # Unsupported so far. More hackery than I want to work on right now # assert_equal ['/path'], Dir['/path*'] end @@ -445,7 +452,7 @@ class FakeFSTest < Test::Unit::TestCase FileUtils.ln_s 'subdir', 'new' assert_equal 'works', File.open('new/nother'){|f| f.read } end - + def test_files_can_be_touched FileUtils.touch('touched_file') assert File.exists?('touched_file') From c11312f70c840081d705a1981cb74eaf525fed61 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Sun, 19 Jul 2009 14:16:37 -0700 Subject: [PATCH 04/12] rake --- Rakefile | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Rakefile diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..c96fc5a --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +task :default do + exec "ruby test/fakefs_test.rb" +end From 7d57d483dfd1e767e77467f6cab84d70be8b9359 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Thu, 16 Jul 2009 16:19:03 -0400 Subject: [PATCH 05/12] Implemented File#<< and File#close --- lib/fakefs.rb | 9 +++++++++ test/fakefs_test.rb | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/lib/fakefs.rb b/lib/fakefs.rb index 00a16c9..5d4ae11 100644 --- a/lib/fakefs.rb +++ b/lib/fakefs.rb @@ -193,9 +193,15 @@ module FakeFS @path = path @mode = mode @file = FileSystem.find(path) + @open = true + end + + def close + @open = false end def read + raise IOError.new('closed stream') unless @open @file.content end @@ -208,6 +214,8 @@ module FakeFS end def write(content) + raise IOError.new('closed stream') unless @open + if !File.exists?(@path) @file = FileSystem.add(path, MockFile.new) end @@ -215,6 +223,7 @@ module FakeFS @file.content += content end alias_method :print, :write + alias_method :<<, :write def flush; self; end end diff --git a/test/fakefs_test.rb b/test/fakefs_test.rb index 17e36d5..2389ab5 100644 --- a/test/fakefs_test.rb +++ b/test/fakefs_test.rb @@ -94,6 +94,14 @@ class FakeFSTest < Test::Unit::TestCase assert_equal "Yatta!", File.read(path) end + def test_can_write_to_files + path = '/path/to/file.txt' + File.open(path, 'w') do |f| + f << 'Yada Yada' + end + assert_equal 'Yada Yada', File.read(path) + end + def test_can_read_with_File_readlines path = '/path/to/file.txt' File.open(path, 'w') do |f| @@ -104,6 +112,16 @@ class FakeFSTest < Test::Unit::TestCase assert_equal ["Yatta!", "woot"], File.readlines(path) end + def test_File_close_disallows_further_access + path = '/path/to/file.txt' + file = File.open(path, 'w') + file.write 'Yada' + file.close + assert_raise IOError do + file.read + end + end + def test_can_read_from_file_objects path = '/path/to/file.txt' File.open(path, 'w') do |f| From 4a02bfff2275149978e84650d69e88a2eda57fd8 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Thu, 16 Jul 2009 16:18:43 -0400 Subject: [PATCH 06/12] Added verify.rb to find gaps in FakeFS --- test/verify.rb | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 test/verify.rb diff --git a/test/verify.rb b/test/verify.rb new file mode 100644 index 0000000..9fa1ff7 --- /dev/null +++ b/test/verify.rb @@ -0,0 +1,27 @@ +# Figure out what's missing from fakefs +# +# USAGE +# +# $ ruby test/verify.rb | grep "not implemented" +require 'fakefs' +require 'test/unit' + +class FakeFSVerifierTest < Test::Unit::TestCase + (RealFile.methods - Class.new.methods).each do |name| + define_method("test #{name} class method") do + assert File.respond_to?(name), "File.#{name} not implemented" + end + end + + (RealFile.instance_methods - Enumerable.instance_methods).each do |name| + define_method("test #{name} instance method") do + assert File.instance_methods.include?(name), "File##{name} not implemented" + end + end + + (RealFileUtils.methods - Class.new.methods).each do |name| + define_method("test #{name} module method") do + assert FileUtils.respond_to?(name), "FileUtils.#{name} not implemented" + end + end +end From eb634265e6380726fd296551217e86dae76f7236 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Sun, 19 Jul 2009 14:23:02 -0700 Subject: [PATCH 07/12] do a deep copy of the hash --- lib/fakefs.rb | 2 +- test/fakefs_test.rb | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/fakefs.rb b/lib/fakefs.rb index 5d4ae11..1e3c388 100644 --- a/lib/fakefs.rb +++ b/lib/fakefs.rb @@ -387,7 +387,7 @@ module FakeFS end def clone(parent) - clone = super() + clone = Marshal.load(Marshal.dump(self)) clone.each do |key, value| value.parent = parent end diff --git a/test/fakefs_test.rb b/test/fakefs_test.rb index 2389ab5..8d32d63 100644 --- a/test/fakefs_test.rb +++ b/test/fakefs_test.rb @@ -121,7 +121,7 @@ class FakeFSTest < Test::Unit::TestCase file.read end end - + def test_can_read_from_file_objects path = '/path/to/file.txt' File.open(path, 'w') do |f| @@ -197,8 +197,10 @@ class FakeFSTest < Test::Unit::TestCase FileUtils.mkdir_p '/path/bar' File.open('/path/bar/baz', 'w'){|f| f.write 'foo' } + FileUtils.cp_r '/path/bar', '/path/bar2' + assert_equal ['/path'], Dir['/path'] - assert_equal ['/path/bar', '/path/foo', '/path/foobar'], Dir['/path/*'] + assert_equal %w( /path/bar /path/bar2 /path/foo /path/foobar ), Dir['/path/*'] assert_equal ['/path/bar/baz'], Dir['/path/bar/*'] From a7f20095f0362a3cefb5a49f86ebb28c609e5da7 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Sun, 19 Jul 2009 15:23:42 -0700 Subject: [PATCH 08/12] fix random cloning bugs --- lib/fakefs.rb | 28 +++++++++++++++++++--------- test/fakefs_test.rb | 12 ++++++++++++ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/lib/fakefs.rb b/lib/fakefs.rb index 1e3c388..7529583 100644 --- a/lib/fakefs.rb +++ b/lib/fakefs.rb @@ -38,10 +38,10 @@ module FakeFS end if dst_file and File.directory?(dst_file) - FileSystem.add(File.join(dest, src), src_file.entry.clone(dest)) + FileSystem.add(File.join(dest, src), src_file.entry.clone(dst_file)) else FileSystem.delete(dest) - FileSystem.add(dest, src_file.entry.clone(dest)) + FileSystem.add(dest, src_file.entry.clone) end end @@ -64,18 +64,18 @@ module FakeFS # about and cleaned up. if new_dir if src[-2..-1] == '/.' - dir.values.each{|f| new_dir[f.name] = f } + dir.values.each{|f| new_dir[f.name] = f.clone(new_dir) } else new_dir[dir.name] = dir.entry.clone(new_dir) end else - FileSystem.add(dest, dir.entry.clone(dest)) + FileSystem.add(dest, dir.entry.clone) end end def mv(src, dest) if target = FileSystem.find(src) - FileSystem.add(dest, target.entry.clone(dest)) + FileSystem.add(dest, target.entry.clone) FileSystem.delete(src) else raise Errno::ENOENT, src @@ -353,15 +353,16 @@ module FakeFS class MockFile attr_accessor :name, :parent, :content + def initialize(name = nil, parent = nil) @name = name @parent = parent @content = '' end - def clone(parent) + def clone(parent = nil) clone = super() - clone.parent = parent + clone.parent = parent if parent clone end @@ -369,6 +370,10 @@ module FakeFS self end + def inspect + "(MockFile name:#{name.inspect} parent:#{parent.to_s.inspect} size:#{content.size})" + end + def to_s File.join(parent.to_s, name) end @@ -386,11 +391,16 @@ module FakeFS self end - def clone(parent) + def inspect + "(MockDir name:#{name.inspect} parent:#{parent.to_s.inspect} size:#{size})" + end + + def clone(parent = nil) clone = Marshal.load(Marshal.dump(self)) clone.each do |key, value| - value.parent = parent + value.parent = clone end + clone.parent = parent if parent clone end diff --git a/test/fakefs_test.rb b/test/fakefs_test.rb index 8d32d63..aee941f 100644 --- a/test/fakefs_test.rb +++ b/test/fakefs_test.rb @@ -422,6 +422,18 @@ class FakeFSTest < Test::Unit::TestCase assert_equal 'footext', File.open('symdir/subdir/foo'){|f| f.read } end + def test_cp_r_sets_parent_correctly + FileUtils.mkdir_p '/path/foo' + File.open('/path/foo/bar', 'w'){|f| f.write 'foo' } + File.open('/path/foo/baz', 'w'){|f| f.write 'foo' } + + FileUtils.cp_r '/path/foo', '/path/bar' + + assert File.exists?('/path/bar/baz') + FileUtils.rm_rf '/path/bar/baz' + assert_equal %w( /path/bar/bar ), Dir['/path/bar/*'] + end + def test_clone_clones_normal_files RealFile.open(here('foo'), 'w'){|f| f.write 'bar' } assert !File.exists?(here('foo')) From 1226acc4b3c4a0c1ff306cdd904cddd8bbedaf8b Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Tue, 21 Jul 2009 22:31:36 -0700 Subject: [PATCH 09/12] File.exist? should return a real boolean (nicer debugging) --- lib/fakefs.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fakefs.rb b/lib/fakefs.rb index 7529583..3e68f18 100644 --- a/lib/fakefs.rb +++ b/lib/fakefs.rb @@ -117,7 +117,7 @@ module FakeFS end def self.exist?(path) - FileSystem.find(path) || false + !!FileSystem.find(path) end class << self From c6c604a3caf5e5eb63c7db2634e30eaa0e8cae72 Mon Sep 17 00:00:00 2001 From: Tymon Tobolski Date: Mon, 20 Jul 2009 15:42:20 +0200 Subject: [PATCH 10/12] Implemented FileUtils#cd (chdir) --- lib/fakefs.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/fakefs.rb b/lib/fakefs.rb index 3e68f18..04f3d7d 100644 --- a/lib/fakefs.rb +++ b/lib/fakefs.rb @@ -107,6 +107,12 @@ module FakeFS end end end + + def cd(dir) + FileSystem.chdir(dir) + end + + alias :chdir :cd end class File From d975149d6f05ab7572c4d50ab64d79573489918b Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Wed, 22 Jul 2009 00:23:44 -0700 Subject: [PATCH 11/12] alias_method, not alias --- lib/fakefs.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/fakefs.rb b/lib/fakefs.rb index 04f3d7d..50b9dea 100644 --- a/lib/fakefs.rb +++ b/lib/fakefs.rb @@ -111,8 +111,7 @@ module FakeFS def cd(dir) FileSystem.chdir(dir) end - - alias :chdir :cd + alias_method :chdir, :cd end class File From 29dd6078699085c9a5fc97cc2ea43b8c904eed31 Mon Sep 17 00:00:00 2001 From: Tymon Tobolski Date: Mon, 20 Jul 2009 16:01:48 +0200 Subject: [PATCH 12/12] Implemented FileUtils#rm_r --- README.markdown | 6 ++++++ lib/fakefs.rb | 1 + 2 files changed, 7 insertions(+) diff --git a/README.markdown b/README.markdown index c4dbf91..52acf1a 100644 --- a/README.markdown +++ b/README.markdown @@ -31,6 +31,12 @@ FakeFS provides a test suite and works with symlinks. It's also strictly a test-time dependency: your actual library does not need to use or know about FakeFS. + +Speed? +------ +http://gist.github.com/150348 + + Authors ------- diff --git a/lib/fakefs.rb b/lib/fakefs.rb index 50b9dea..0d85386 100644 --- a/lib/fakefs.rb +++ b/lib/fakefs.rb @@ -19,6 +19,7 @@ module FakeFS FileSystem.delete(path) end alias_method :rm_rf, :rm + alias_method :rm_r, :rm def ln_s(target, path) raise Errno::EEXIST, path if FileSystem.find(path)