[DRE-commits] [ruby-fakefs] 01/09: Imported Upstream version 0.6.7

Sebastian Boehm sometimesfood-guest at moszumanska.debian.org
Thu Apr 30 18:52:00 UTC 2015


This is an automated email from the git hooks/post-receive script.

sometimesfood-guest pushed a commit to branch master
in repository ruby-fakefs.

commit d3d9636eae6b6435aa21353821c1a581371af4b8
Author: Sebastian Boehm <sebastian at sometimesfood.org>
Date:   Thu Apr 30 15:45:15 2015 +0200

    Imported Upstream version 0.6.7
---
 .gitignore                                         |   12 +
 .rubocop.yml                                       |   45 +
 .travis.yml                                        |    8 +-
 CONTRIBUTORS                                       |   69 +-
 Gemfile                                            |    8 +-
 Gemfile.lock                                       |   31 -
 README.markdown                                    |   27 +-
 Rakefile                                           |   76 +-
 etc/git-rank-contributors                          |   57 +
 fakefs.gemspec                                     |  102 +-
 lib/fakefs/base.rb                                 |   33 +-
 lib/fakefs/dir.rb                                  |  135 +-
 lib/fakefs/fake/dir.rb                             |    8 +-
 lib/fakefs/fake/file.rb                            |   32 +-
 lib/fakefs/fake/symlink.rb                         |    9 +-
 lib/fakefs/file.rb                                 |  346 ++--
 lib/fakefs/file_system.rb                          |  106 +-
 lib/fakefs/file_test.rb                            |   23 +-
 lib/fakefs/fileutils.rb                            |  235 ++-
 lib/fakefs/kernel.rb                               |   43 +
 lib/fakefs/pathname.rb                             |  568 ++++---
 lib/fakefs/safe.rb                                 |    4 +-
 lib/fakefs/spec_helpers.rb                         |   54 +-
 lib/fakefs/version.rb                              |    3 +-
 metadata.yml                                       |  142 +-
 spec/fakefs/fakefs_bug_ruby_2.1.0-preview2_spec.rb |   18 +
 spec/fakefs/spec_helpers_spec.rb                   |   83 +-
 test/dir/tempfile_test.rb                          |   21 +
 test/fake/file/join_test.rb                        |    9 +-
 test/fake/file/lstat_test.rb                       |   47 +-
 test/fake/file/stat_test.rb                        |   25 +-
 test/fake/file/sysseek_test.rb                     |   31 +-
 test/fake/file/syswrite_test.rb                    |   51 +-
 test/fake/file_test.rb                             |   41 +-
 test/fake/symlink_test.rb                          |   31 +-
 test/fakefs_test.rb                                | 1686 +++++++++++++-------
 test/file/stat_test.rb                             |  111 +-
 test/kernel_test.rb                                |   53 +
 test/pathname_test.rb                              |   75 +
 test/safe_test.rb                                  |   28 +-
 test/test_helper.rb                                |   34 +-
 test/verify.rb                                     |   15 +-
 42 files changed, 3085 insertions(+), 1450 deletions(-)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a5292c7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+*.sw?
+pkg
+Gemfile.lock
+.rbenv-version
+docs
+pkg
+.rbx
+.idea
+.bundle
+.project
+.ruby-version
+Gemfile.lock
diff --git a/.rubocop.yml b/.rubocop.yml
new file mode 100644
index 0000000..2140186
--- /dev/null
+++ b/.rubocop.yml
@@ -0,0 +1,45 @@
+AllCops:
+  Include:
+    - '**/Gemfile'
+    - lib/**/*
+    - spec/**/*
+    - gemirro.gemspec
+  Exclude:
+    - files/**/*
+    - templates/**/*
+    - etc/**/*
+MethodLength:
+  Exclude:
+    - lib/**/*
+    - test/**/*.rb
+    - spec/**/*.rb
+ClassLength:
+  Enabled: false
+LineLength:
+  Exclude:
+    - test/**/*
+ParameterLists:
+  Enabled: false
+Metrics/CyclomaticComplexity:
+  Severity: warning
+  Max: 20
+Metrics/PerceivedComplexity:
+  Severity: warning
+  Max: 20
+Lint/Eval:
+  Enabled: false
+Metrics/BlockNesting:
+  Severity: warning
+  Max: 4
+Metrics/AbcSize:
+  Enabled: false
+Style/PredicateName:
+  Exclude:
+    - lib/fakefs/file.rb
+Style/MethodName:
+  Enabled: false
+Style/ModuleFunction:
+  Enabled: false
+TrivialAccessors:
+  Enabled: true
+  ExactNameMatch: true
diff --git a/.travis.yml b/.travis.yml
index 97030f9..025ddd2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,9 +1,15 @@
+language: ruby
+sudo: false
 rvm:
-  - 1.8.7
   - 1.9.3
+  - 2.0.0
+  - 2.1.1
+  - 2.2.0
   - jruby
   - rbx-19mode
 matrix:
   allow_failures:
     - rvm: jruby
     - rvm: rbx-19mode
+before_install:
+  - gem --version
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 3a342a2..f8f3118 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -1,35 +1,92 @@
 Scott Taylor <scott at railsnewbie.com>
+Pierre RAMBAUD <pierre.rambaud at numergy.com>
 Pat Nakajima <patnakajima at gmail.com>
 Chris Wanstrath <chris at ozmm.org>
+Lukas Oberhuber <lukaso at gmail.com>
+Brian Donovan <donovan at squareup.com>
 Myles Eftos <myles at madpilot.com.au>
 Jeff Hodges <jeff at somethingsimilar.com>
+Jakub Jirutka <jakub at jirutka.cz>
+Pierre RAMBAUD <pierre.rambaud86 at gmail.com>
+Morten Møller Riis <mortenmoellerriis at gmail.com>
 Matt Freels <matt at freels.name>
 Eero Saynatkari <projects at kittensoft.org>
+Andres Riofrio <riofrios at gmail.com>
+Brian Donovan <me at brian-donovan.com>
+Jacob Evans <jacob at dekz.net>
 Víctor Martínez <knoopx at gmail.com>
+Mariusz Pietrzyk <wijet at wijet.pl>
+John Firebaugh <john.firebaugh at gmail.com>
+Sebastian Boehm <sebastian at sometimesfood.org>
+Dan Duvall <dduvall at wikimedia.org>
+Carlos Pardo <cpardo at altavistaed.com>
+AlphaHydrae <hydrae.alpha at gmail.com>
 Nick Quaranto <nick at quaran.to>
+Toby Ovod-Everett <toby at ovod-everett.org>
 Aaron Suggs <aaron at ktheory.com>
 Victor Costan <costan at gmail.com>
+Mateusz Juraszek <meceo00 at gmail.com>
 Eric MSP Veith <eveith at wwweb-library.net>
+Leigh Caplan <lcaplan at onehub.com>
+Daniel Dyba <daniel.dyba at gmail.com>
+Maarten Hoogendoorn <maarten at moretea.nl>
 Jon Yurek <jyurek at thoughtbot.com>
 Jared Luxenberg <jared at jaredlux.com>
-Lars Gierth <lars.gierth at gmail.com>
+DSIW <dsiw at dsiw-it.de>
+doc75 <github at virlet.org>
 Greg Campbell <gtcampbell at gmail.com>
+Lars Gierth <lars.gierth at gmail.com>
+marano <thiagomarano at gmail.com>
 Ben Mabey <ben at benmabey.com>
+Jorge Orlando Munoz <jmunoz at altavistaed.com>
 Mark <mark at amerine.net>
 Sam Goldstein <sam at aboutus.org>
-Ryan McGeary <ryan at mcgeary.org>
+Adam Alboyadjian <adam at vistahigherlearning.com>
+Rick Salevsky <rsalevsky at suse.com>
+Scott Petersen <petersen at centtech.com>
+Matt Todd <chiology at gmail.com>
 Noah Paessel <knowuh at gmail.com>
+Emil Soman <emil.soman at gmail.com>
+Ryan McGeary <ryan at mcgeary.org>
 dmathieu <42 at dmathieu.com>
-Mariusz Pietrzyk <wijet at wijet.pl>
-marano <thiagomarano at gmail.com>
+Oleg Sukhodolsky <os97673 at gmail.com>
+Winston Lee <lee.winston at gmail.com>
+Radek Simko <radek.simko at gmail.com>
+Grayson Wright <wright.grayson at gmail.com>
+Zequez <zequez at gmail.com>
 jameswilding <james at jameswilding.net>
+Ed Ruder <ed at squareup.com>
 Tymon Tobolski <i at teamon.eu>
+Benjamin Oakes <hello at benjaminoakes.com>
 Scott Barron <scott at elitists.net>
 Andrius Chamentauskas <andrius.chamentauskas at gmail.com>
+Eric Daspet <eric.daspet at survol.fr>
+W. Andrew Loe III <andrew at andrewloe.com>
+Matt Hoyle <matt at deployable.co>
+Xavier Shay <xavier at squareup.com>
+Travis Herrick <travis at carbonfive.com>
 Keita Urashima <ursm at ursm.jp>
-David Reese <david at whatcould.com>
+rambutan <usul at usul-HP-EliteBook-8460p.(none)>
+Matthew Morgan <lytithwyn at gmail.com>
+= <gokulnath at mobme.in>
+andrea longhi <andrea at spaghetticode.it>
 msassak <msassak at gmail.com>
-Andrius Chamentauskas <sinsiliux at gmail.com>
+David Reese <david at whatcould.com>
 timo3377 <tim.linquist at gmail.com>
+Andrius Chamentauskas <sinsiliux at gmail.com>
+Paolo Gianrossi <paolino.gianrossi at gmail.com>
+Matt Rogers <mattrogers at sbcglobal.net>
+Michael Scherer <misc at zarb.org>
 Mislav Marohnić <mislav.marohnic at gmail.com>
+Andrew Ryan <nerdrew at gmail.com>
 Rob Sanheim <rsanheim at gmail.com>
+Chris Wanstrath <chris at github.com>
+Chris Knadler <takeshi91k at gmail.com>
+Toon Willems <willemstoon at gmail.com>
+Ryan Scott Lewis <ryanscottlewis at lewis-software.com>
+Sven Riedel <sr at gimp.org>
+Dane O'Connor <dane.oconnor at gmail.com>
+Yuta Shimizu <pachirel at gmail.com>
+Benjamin Fleischer <github at benjaminfleischer.com>
+Jordi Massaguer Pla <jmassaguerpla at suse.de>
+Maria Shaldibina <mariash at pivotallabs.com>
diff --git a/Gemfile b/Gemfile
index 5fa8abb..e088013 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,7 +1,3 @@
-source :rubygems
+source 'https://rubygems.org/'
 
-group :development do
-  gem 'rspec'
-  gem 'jeweler'
-  gem 'rdiscount'
-end
\ No newline at end of file
+gemspec
diff --git a/Gemfile.lock b/Gemfile.lock
deleted file mode 100644
index 348667e..0000000
--- a/Gemfile.lock
+++ /dev/null
@@ -1,31 +0,0 @@
-GEM
-  remote: http://rubygems.org/
-  specs:
-    diff-lcs (1.1.3)
-    git (1.2.5)
-    jeweler (1.8.4)
-      bundler (~> 1.0)
-      git (>= 1.2.5)
-      rake
-      rdoc
-    json (1.7.5)
-    rake (10.0.0)
-    rdiscount (1.6.8)
-    rdoc (3.12)
-      json (~> 1.4)
-    rspec (2.12.0)
-      rspec-core (~> 2.12.0)
-      rspec-expectations (~> 2.12.0)
-      rspec-mocks (~> 2.12.0)
-    rspec-core (2.12.0)
-    rspec-expectations (2.12.0)
-      diff-lcs (~> 1.1.3)
-    rspec-mocks (2.12.0)
-
-PLATFORMS
-  ruby
-
-DEPENDENCIES
-  jeweler
-  rdiscount
-  rspec
diff --git a/README.markdown b/README.markdown
index 23c90d4..ff50829 100644
--- a/README.markdown
+++ b/README.markdown
@@ -1,4 +1,4 @@
-FakeFS [![build status](https://secure.travis-ci.org/defunkt/fakefs.png)](https://secure.travis-ci.org/defunkt/fakefs)
+FakeFS [![build status](https://secure.travis-ci.org/defunkt/fakefs.svg?branch=master)](https://secure.travis-ci.org/defunkt/fakefs)
 ======
 
 Mocha is great. But when your library is all about manipulating the
@@ -59,9 +59,12 @@ end
 Rails
 -----
 
-If you are using fakefs in a rails project with bundler, you'll probably want to specify the following in your Gemfile:
+If you are using fakefs in a rails project with bundler, you'll probably want
+to specify the following in your Gemfile:
 
-  gem "fakefs", :require => "fakefs/safe"
+``` ruby
+gem "fakefs", :require => "fakefs/safe"
+```
 
 
 RSpec
@@ -114,6 +117,15 @@ FakeFS internally uses the `Pathname` and `FileUtils` constants. If you use
 these in your app, be certain you're properly requiring them and not counting
 on FakeFS' own require.
 
+As of v0.5.0, FakeFS's current working directory (i.e. `Dir.pwd`) is
+independent of the real working directory. Previously if the real working
+directory were, for example, `/Users/donovan/Desktop`, then FakeFS would use
+that as the fake working directory too, even though it most likely didn't
+exist. This caused all kinds of subtle bugs. Now the default working directory
+is the only thing that is guaranteed to exist, namely the root (i.e. `/`). This
+may be important when upgrading from v0.4.x to v0.5.x, especially if you depend
+on the real working directory while using FakeFS.
+
 
 Speed?
 ------
@@ -128,10 +140,6 @@ Installation
 
     $ gem install fakefs
 
-### [Rip](http://hellorip.com)
-
-    $ rip install git://github.com/defunkt/fakefs.git
-
 
 Contributing
 ------------
@@ -149,9 +157,8 @@ Meta
 
 * Code: `git clone git://github.com/defunkt/fakefs.git`
 * Home: <http://github.com/defunkt/fakefs>
-* Docs: <http://defunkt.github.com/fakefs>
+* Docs: <http://rdoc.info/github/defunkt/fakefs>
 * Bugs: <http://github.com/defunkt/fakefs/issues>
-* List: <http://groups.google.com/group/fakefs>
 * Test: <http://travisci.org/#!/defunkt/fakefs>
 * Gems: <http://rubygems.org/gems/fakefs>
 
@@ -163,4 +170,4 @@ Releasing
 
 1. Update version in lib/fakefs/version.rb
 2. Commit it
-3. rake publish
+3. run `bundle exec rake publish`
diff --git a/Rakefile b/Rakefile
index 4161356..651b5f0 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,62 +1,62 @@
 $LOAD_PATH.unshift File.join(File.dirname(__FILE__))
 $LOAD_PATH.unshift File.join(File.dirname(__FILE__), 'test')
 
-require "bundler/setup"
-
+require 'bundler/setup'
 require 'rake/testtask'
+require File.expand_path(File.join(File.dirname(__FILE__), "lib", "fakefs", "version"))
 
 Rake::TestTask.new do |t|
-  t.libs << "test"
+  t.libs << 'test'
   t.test_files = FileList['test/**/*test.rb']
   t.verbose = true
 end
 
 begin
   require 'rspec/core/rake_task'
-  desc "Run specs"
+  desc 'Run specs'
   RSpec::Core::RakeTask.new
 rescue LoadError
   puts "Spec task can't be loaded. `gem install rspec`"
 end
 
-task :default => [:test, :spec]
-
 begin
-  require 'jeweler'
-
-  $LOAD_PATH.unshift File.dirname(__FILE__) + '/lib'
-  require 'fakefs/version'
-
-  Jeweler::Tasks.new do |gemspec|
-    gemspec.name        = "fakefs"
-    gemspec.summary     = "A fake filesystem. Use it in your tests."
-    gemspec.email       = "chris at ozmm.org"
-    gemspec.homepage    = "http://github.com/defunkt/fakefs"
-    gemspec.description = "A fake filesystem. Use it in your tests."
-    gemspec.authors     = ["Chris Wanstrath", "Scott Taylor", "Jeff Hodges", "Pat Nakajima"]
-    gemspec.has_rdoc    = false
-    gemspec.version     = FakeFS::Version.to_s
-  end
+  require 'rubocop/rake_task'
+  desc 'Run RuboCop'
+  RuboCop::RakeTask.new(:rubocop)
 rescue LoadError
-  puts "Jeweler not available."
-  puts "Install it with: gem install jeweler"
+  puts "Rubocop task can't be loaded. `gem install rubocop`"
 end
 
-desc "Build a gem"
-task :gem => [ :gemspec, :build ]
-
-desc "Push a new version to Gemcutter"
-task :publish => [ :gemspec, :build ] do
-  abort("Tests failed!") unless system("rake test")
-  system "git tag v#{FakeFS::Version}"
-  system "git push origin v#{FakeFS::Version}"
-  system "git push origin master"
-  system "gem push pkg/fakefs-#{FakeFS::Version}.gem"
-  system "git clean -fd"
-  exec "rake pages"
-end
+task default: [:test, :spec, :rubocop]
 
-desc "Update contributors"
+desc 'Push a new version to rubygems.org'
+task :publish => [:test, :spec, :rubocop, :update_contributors, :tag, :release, :push]
+
+desc 'Update contributors'
 task :update_contributors do
-  sh "git-rank-contributors > CONTRIBUTORS"
+  git_rank_contributors = "#{File.dirname(File.expand_path(__FILE__))}/etc/git-rank-contributors"
+
+  sh "#{git_rank_contributors} > CONTRIBUTORS"
+  if `git status | grep CONTRIBUTORS`.strip.length > 0
+    sh "git add CONTRIBUTORS"
+    sh "git commit -m 'Update contributors for release'"
+  end
+end
+
+desc 'Release a new version'
+task :release do
+  sh "gem build fakefs.gemspec"
+  sh "gem push fakefs-*.gem"
+end
+
+desc 'tag'
+task :tag do
+  version = FakeFS::Version::VERSION
+  sh "git tag v#{version}"
+  sh "git push --tags"
+end
+
+desc 'Run git push'
+task :push do
+  sh "git push origin master"
 end
diff --git a/etc/git-rank-contributors b/etc/git-rank-contributors
new file mode 100755
index 0000000..88eb4c4
--- /dev/null
+++ b/etc/git-rank-contributors
@@ -0,0 +1,57 @@
+#!/usr/bin/env ruby
+
+## git-rank-contributors: a simple script to trace through the logs and
+## rank contributors by the total size of the diffs they're responsible for.
+## A change counts twice as much as a plain addition or deletion.
+##
+## Output may or may not be suitable for inclusion in a CREDITS file.
+## Probably not without some editing, because people often commit from more
+## than one address.
+##
+## git-rank-contributors Copyright 2008 William Morgan <wmorgan-git-wt-add at masanjin.net>.
+## This program is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or (at
+## your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You can find the GNU General Public License at:
+##   http://www.gnu.org/licenses/
+
+class String
+  def obfuscate; gsub(/@/, " at the ").gsub(/\.(\w+)(>|$)/, ' dot \1s\2') end
+end
+
+lines = {}
+verbose = ARGV.delete("-v")
+obfuscate = ARGV.delete("-o")
+
+author = nil
+state = :pre_author
+`git log -p --no-color`.lines.each do |l|
+  case
+  when (state == :pre_author || state == :post_author) && l =~ /Author: (.*)$/
+    author = $1
+    state = :post_author
+    lines[author] ||= 0
+  when state == :post_author && l =~ /^\+\+\+/
+    state = :in_diff
+  when state == :in_diff && l =~ /^[\+\-]/
+    lines[author] += 1
+  when state == :in_diff && l =~ /^commit /
+    state = :pre_author
+  end
+end
+
+lines.sort_by { |a, c| -c }.each do |a, c|
+  a = a.obfuscate if obfuscate
+  if verbose
+    puts "#{a}: #{c} lines of diff"
+  else
+    puts a
+  end
+end
diff --git a/fakefs.gemspec b/fakefs.gemspec
index 00539a5..ca0d45a 100644
--- a/fakefs.gemspec
+++ b/fakefs.gemspec
@@ -1,83 +1,27 @@
-# Generated by jeweler
-# DO NOT EDIT THIS FILE DIRECTLY
-# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
-# -*- encoding: utf-8 -*-
+# coding: utf-8
+lib = File.expand_path('../lib', __FILE__)
+$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
+require 'fakefs/version'
 
-Gem::Specification.new do |s|
-  s.name = "fakefs"
-  s.version = "0.4.2"
+Gem::Specification.new do |spec|
+  spec.name          = "fakefs"
+  spec.version       = FakeFS::Version.to_s
+  spec.authors       = ["Chris Wanstrath", "Scott Taylor", "Jeff Hodges", "Pat Nakajima", "Brian Donovan"]
+  spec.email         = ["chris at ozmm.org"]
+  spec.description   = %q{A fake filesystem. Use it in your tests.}
+  spec.summary       = %q{A fake filesystem. Use it in your tests.}
+  spec.homepage      = "http://github.com/defunkt/fakefs"
+  spec.license       = "MIT"
 
-  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
-  s.authors = ["Chris Wanstrath", "Scott Taylor", "Jeff Hodges", "Pat Nakajima"]
-  s.date = "2012-11-24"
-  s.description = "A fake filesystem. Use it in your tests."
-  s.email = "chris at ozmm.org"
-  s.extra_rdoc_files = [
-    "LICENSE",
-    "README.markdown"
-  ]
-  s.files = [
-    ".autotest",
-    ".rspec",
-    ".travis.yml",
-    "CONTRIBUTORS",
-    "Gemfile",
-    "Gemfile.lock",
-    "LICENSE",
-    "README.markdown",
-    "Rakefile",
-    "fakefs.gemspec",
-    "lib/fakefs.rb",
-    "lib/fakefs/base.rb",
-    "lib/fakefs/dir.rb",
-    "lib/fakefs/fake/dir.rb",
-    "lib/fakefs/fake/file.rb",
-    "lib/fakefs/fake/symlink.rb",
-    "lib/fakefs/file.rb",
-    "lib/fakefs/file_system.rb",
-    "lib/fakefs/file_test.rb",
-    "lib/fakefs/fileutils.rb",
-    "lib/fakefs/pathname.rb",
-    "lib/fakefs/safe.rb",
-    "lib/fakefs/spec_helpers.rb",
-    "lib/fakefs/version.rb",
-    "spec/fakefs/spec_helpers_spec.rb",
-    "spec/spec.opts",
-    "spec/spec_helper.rb",
-    "test/fake/file/join_test.rb",
-    "test/fake/file/lstat_test.rb",
-    "test/fake/file/stat_test.rb",
-    "test/fake/file/sysseek_test.rb",
-    "test/fake/file/syswrite_test.rb",
-    "test/fake/file_test.rb",
-    "test/fake/symlink_test.rb",
-    "test/fakefs_test.rb",
-    "test/file/stat_test.rb",
-    "test/safe_test.rb",
-    "test/test_helper.rb",
-    "test/verify.rb"
-  ]
-  s.homepage = "http://github.com/defunkt/fakefs"
-  s.require_paths = ["lib"]
-  s.rubygems_version = "1.8.24"
-  s.summary = "A fake filesystem. Use it in your tests."
+  spec.files         = `git ls-files`.split($/)
+  spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
+  spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
+  spec.require_paths = ["lib"]
 
-  if s.respond_to? :specification_version then
-    s.specification_version = 3
-
-    if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
-      s.add_development_dependency(%q<rspec>, [">= 0"])
-      s.add_development_dependency(%q<jeweler>, [">= 0"])
-      s.add_development_dependency(%q<rdiscount>, [">= 0"])
-    else
-      s.add_dependency(%q<rspec>, [">= 0"])
-      s.add_dependency(%q<jeweler>, [">= 0"])
-      s.add_dependency(%q<rdiscount>, [">= 0"])
-    end
-  else
-    s.add_dependency(%q<rspec>, [">= 0"])
-    s.add_dependency(%q<jeweler>, [">= 0"])
-    s.add_dependency(%q<rdiscount>, [">= 0"])
-  end
+  spec.add_development_dependency "bundler", "~> 1.3"
+  spec.add_development_dependency "rake", "~> 10.3"
+  spec.add_development_dependency "rspec", "~> 3.1"
+  spec.add_development_dependency 'rubocop', '~>0.25'
+  spec.add_development_dependency 'minitest', '~> 5.5'
+  spec.add_development_dependency 'minitest-rg', '~> 5.1'
 end
-
diff --git a/lib/fakefs/base.rb b/lib/fakefs/base.rb
index 6f66ce8..aebb2f2 100644
--- a/lib/fakefs/base.rb
+++ b/lib/fakefs/base.rb
@@ -4,47 +4,62 @@ RealFileUtils       = FileUtils
 RealDir             = Dir
 RealPathname        = Pathname
 
+def RealPathname(*args)
+  RealPathname.new(*args)
+end
+
+if RUBY_VERSION >= '1.9.3'
+  def Pathname(*args)
+    Pathname.new(*args)
+  end
+end
+
+# FakeFS module
 module FakeFS
-  @activated = false
   class << self
     def activated?
-      @activated
+      @activated ? true : false
     end
 
     def activate!
-      @activated = true
       Object.class_eval do
         remove_const(:Dir)
         remove_const(:File)
         remove_const(:FileTest)
         remove_const(:FileUtils)
-        remove_const(:Pathname) if RUBY_VERSION >= "1.9.3"
+        remove_const(:Pathname) if RUBY_VERSION >= '1.9.3'
 
         const_set(:Dir,       FakeFS::Dir)
         const_set(:File,      FakeFS::File)
         const_set(:FileUtils, FakeFS::FileUtils)
         const_set(:FileTest,  FakeFS::FileTest)
-        const_set(:Pathname,  FakeFS::Pathname) if RUBY_VERSION >= "1.9.3"
+        const_set(:Pathname,  FakeFS::Pathname) if RUBY_VERSION >= '1.9.3'
+        ::FakeFS::Kernel.hijack!
       end
+
+      @activated = true
+
       true
     end
 
     def deactivate!
-      @activated = false
-
       Object.class_eval do
         remove_const(:Dir)
         remove_const(:File)
         remove_const(:FileTest)
         remove_const(:FileUtils)
-        remove_const(:Pathname) if RUBY_VERSION >= "1.9.3"
+        remove_const(:Pathname) if RUBY_VERSION >= '1.9.3'
 
         const_set(:Dir,       RealDir)
         const_set(:File,      RealFile)
         const_set(:FileTest,  RealFileTest)
         const_set(:FileUtils, RealFileUtils)
-        const_set(:Pathname,  RealPathname) if RUBY_VERSION >= "1.9.3"
+        const_set(:Pathname,  RealPathname) if RUBY_VERSION >= '1.9.3'
+        ::FakeFS::Kernel.unhijack!
       end
+
+      @activated = false
+
       true
     end
 
diff --git a/lib/fakefs/dir.rb b/lib/fakefs/dir.rb
index d5c0314..675f4f0 100644
--- a/lib/fakefs/dir.rb
+++ b/lib/fakefs/dir.rb
@@ -1,18 +1,20 @@
 module FakeFS
+  # FakeFs Dir class
   class Dir
     include Enumerable
+    attr_reader :path
 
     def self._check_for_valid_file(path)
-      raise Errno::ENOENT, "No such file or directory - #{path}" unless FileSystem.find(path)
+      fail Errno::ENOENT, path unless FileSystem.find(path)
     end
 
     def initialize(string)
       self.class._check_for_valid_file(string)
 
-      @path = string
+      @path = FileSystem.normalize_path(string)
       @open = true
       @pointer = 0
-      @contents = [ '.', '..', ] + FileSystem.find(@path).entries
+      @contents = ['.', '..'] + FileSystem.find(@path).entries
     end
 
     def close
@@ -22,16 +24,12 @@ module FakeFS
       nil
     end
 
-    def each(&block)
-      while f = read
+    def each(&_block)
+      while (f = read)
         yield f
       end
     end
 
-    def path
-      @path
-    end
-
     def pos
       @pointer
     end
@@ -41,10 +39,16 @@ module FakeFS
     end
 
     def read
-      raise IOError, "closed directory" if @pointer == nil
+      fail IOError, 'closed directory' if @pointer.nil?
       n = @contents[@pointer]
       @pointer += 1
-      n.to_s.gsub(path + '/', '') if n
+      return unless n
+
+      if n.to_s[0, path.size + 1] == path + '/'
+        n.to_s[path.size + 1..-1]
+      else
+        n.to_s
+      end
     end
 
     def rewind
@@ -52,7 +56,7 @@ module FakeFS
     end
 
     def seek(integer)
-      raise IOError, "closed directory" if @pointer == nil
+      fail IOError, 'closed directory' if @pointer.nil?
       @pointer = integer
       @contents[integer]
     end
@@ -62,59 +66,68 @@ module FakeFS
     end
 
     def self.exists?(path)
-      File.exists?(path) && File.directory?(path)
+      File.exist?(path) && File.directory?(path)
     end
 
     def self.chdir(dir, &blk)
       FileSystem.chdir(dir, &blk)
     end
 
-    def self.chroot(string)
-      raise NotImplementedError
+    def self.chroot(_string)
+      fail NotImplementedError
     end
 
     def self.delete(string)
       _check_for_valid_file(string)
-      raise Errno::ENOTEMPTY, "Directory not empty - #{string}" unless FileSystem.find(string).empty?
+      fail Errno::ENOTEMPTY, string unless FileSystem.find(string).empty?
 
       FileSystem.delete(string)
     end
 
-    def self.entries(dirname)
+    def self.entries(dirname, _opts = {})
       _check_for_valid_file(dirname)
 
       Dir.new(dirname).map { |file| File.basename(file) }
     end
 
-    def self.foreach(dirname, &block)
+    def self.foreach(dirname, &_block)
       Dir.open(dirname) { |file| yield file }
     end
 
-    def self.glob(pattern, &block)
+    def self.glob(pattern, _flags = 0, &block)
       matches_for_pattern = lambda do |matcher|
-        [FileSystem.find(matcher) || []].flatten.map{|e|
-          Dir.pwd.match(%r[\A/?\z]) || !e.to_s.match(%r[\A#{Dir.pwd}/?]) ? e.to_s : e.to_s.match(%r[\A#{Dir.pwd}/?]).post_match}.sort
+        [FileSystem.find(matcher) || []].flatten.map do |e|
+          if Dir.pwd.match(/\A\/?\z/) ||
+             !e.to_s.match(/\A#{Dir.pwd}\/?/)
+            e.to_s
+          else
+            e.to_s.match(/\A#{Dir.pwd}\/?/).post_match
+          end
+        end.sort
       end
 
       if pattern.is_a? Array
-        files = pattern.collect { |matcher| matches_for_pattern.call matcher }.flatten
+        files = pattern.map do |matcher|
+          matches_for_pattern.call matcher
+        end.flatten
       else
         files = matches_for_pattern.call pattern
       end
-      return block_given? ? files.each { |file| block.call(file) } : files
+
+      block_given? ? files.each { |file| block.call(file) } : files
     end
 
-    if RUBY_VERSION >= "1.9"
+    if RUBY_VERSION >= '1.9'
       def self.home(user = nil)
         RealDir.home(user)
       end
     end
 
-    def self.mkdir(string, integer = 0)
+    def self.mkdir(string, _integer = 0)
       FileUtils.mkdir(string)
     end
 
-    def self.open(string, &block)
+    def self.open(string, &_block)
       if block_given?
         Dir.new(string).each { |file| yield(file) }
       else
@@ -130,27 +143,84 @@ module FakeFS
       FileSystem.current_dir.to_s
     end
 
+    if RUBY_VERSION >= '2.1'
+      # Tmpname module
+      module Tmpname # :nodoc:
+        module_function
+
+        def tmpdir
+          Dir.tmpdir
+        end
+
+        def make_tmpname(prefix_suffix, n)
+          case prefix_suffix
+          when String
+            prefix = prefix_suffix
+            suffix = ''
+          when Array
+            prefix = prefix_suffix[0]
+            suffix = prefix_suffix[1]
+          else
+            fail ArgumentError,
+                 "unexpected prefix_suffix: #{prefix_suffix.inspect}"
+          end
+          t = Time.now.strftime('%Y%m%d')
+          path = "#{prefix}#{t}-#{$PID}-#{rand(0x100000000).to_s(36)}"
+          path << "-#{n}" if n
+          path << suffix
+        end
+
+        def create(basename, *rest)
+          if (opts = Hash.try_convert(rest[-1]))
+            opts = opts.dup if rest.pop.equal?(opts)
+            max_try = opts.delete(:max_try)
+            opts = [opts]
+          else
+            opts = []
+          end
+          tmpdir, = *rest
+          if $SAFE > 0 && tmpdir.tainted?
+            tmpdir = '/tmp'
+          else
+            tmpdir ||= self.tmpdir
+          end
+          n = nil
+          begin
+            path = File.join(tmpdir, make_tmpname(basename, n))
+            yield(path, n, *opts)
+          rescue Errno::EEXIST
+            n ||= 0
+            n += 1
+            retry if !max_try || n < max_try
+            raise "cannot generate temporary name using `#{basename}' " \
+              "under `#{tmpdir}'"
+          end
+          path
+        end
+      end
+    end
+
     # This code has been borrowed from Rubinius
     def self.mktmpdir(prefix_suffix = nil, tmpdir = nil)
       case prefix_suffix
       when nil
-        prefix = "d"
-        suffix = ""
+        prefix = 'd'
+        suffix = ''
       when String
         prefix = prefix_suffix
-        suffix = ""
+        suffix = ''
       when Array
         prefix = prefix_suffix[0]
         suffix = prefix_suffix[1]
       else
-        raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}"
+        fail ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}"
       end
 
-      t = Time.now.strftime("%Y%m%d")
+      t = Time.now.strftime('%Y%m%d')
       n = nil
 
       begin
-        path = "#{tmpdir}/#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}"
+        path = "#{tmpdir}/#{prefix}#{t}-#{$PID}-#{rand(0x100000000).to_s(36)}"
         path << "-#{n}" if n
         path << suffix
         mkdir(path, 0700)
@@ -180,6 +250,7 @@ module FakeFS
       alias_method :getwd, :pwd
       alias_method :rmdir, :delete
       alias_method :unlink, :delete
+      alias_method :exist?, :exists?
     end
   end
 end
diff --git a/lib/fakefs/fake/dir.rb b/lib/fakefs/fake/dir.rb
index 555cf18..49e0aac 100644
--- a/lib/fakefs/fake/dir.rb
+++ b/lib/fakefs/fake/dir.rb
@@ -1,4 +1,5 @@
 module FakeFS
+  # Fake Dir class
   class FakeDir
     attr_accessor :name, :parent, :mode, :uid, :gid, :mtime, :atime
     attr_reader :ctime, :content
@@ -12,7 +13,7 @@ module FakeFS
       @mode    = 0100000 + (0777 - File.umask)
       @uid     = Process.uid
       @gid     = Process.gid
-      @content = ""
+      @content = ''
       @entries = {}
     end
 
@@ -21,7 +22,8 @@ module FakeFS
     end
 
     def inspect
-      "(FakeDir name:#{name.inspect} parent:#{parent.to_s.inspect} size:#{@entries.size})"
+      "(FakeDir name:#{name.inspect} " \
+      "parent:#{parent.to_s.inspect} size:#{@entries.size})"
     end
 
     def clone(parent = nil)
@@ -52,7 +54,7 @@ module FakeFS
     end
 
     def matches(pattern)
-      @entries.reject {|k,v| pattern !~ k }.values
+      @entries.reject { |k, _v| pattern !~ k }.values
     end
 
     def [](name)
diff --git a/lib/fakefs/fake/file.rb b/lib/fakefs/fake/file.rb
index aa9d6af..b51be36 100644
--- a/lib/fakefs/fake/file.rb
+++ b/lib/fakefs/fake/file.rb
@@ -1,12 +1,16 @@
 module FakeFS
+  # Fake file class
   class FakeFile
     attr_accessor :name, :parent, :content, :mtime, :atime, :mode, :uid, :gid
-    attr_reader :ctime
+    attr_reader :ctime, :birthtime
 
+    # Inode class
     class Inode
       def initialize(file_owner)
-        #1.9.3 when possible set default external encoding
-        @content = "".respond_to?(:encode) ? "".encode(Encoding.default_external) : ""
+        # 1.9.3 when possible set default external encoding
+        @content = ''
+        @content = ''.encode(
+          Encoding.default_external) if ''.respond_to?(:encode)
         @links   = [file_owner]
       end
 
@@ -30,15 +34,16 @@ module FakeFS
     end
 
     def initialize(name = nil, parent = nil)
-      @name   = name
-      @parent = parent
-      @inode  = Inode.new(self)
-      @ctime  = Time.now
-      @mtime  = @ctime
-      @atime  = @ctime
-      @mode   = 0100000 + (0666 - File.umask)
-      @uid    = Process.uid
-      @gid    = Process.gid      
+      @name      = name
+      @parent    = parent
+      @inode     = Inode.new(self)
+      @ctime     = Time.now
+      @mtime     = @ctime
+      @atime     = @ctime
+      @birthtime = @ctime
+      @mode      = 0100000 + (0666 - File.umask)
+      @uid       = Process.uid
+      @gid       = Process.gid
     end
 
     attr_accessor :inode
@@ -71,7 +76,8 @@ module FakeFS
     end
 
     def inspect
-      "(FakeFile name:#{name.inspect} parent:#{parent.to_s.inspect} size:#{content.size})"
+      "(FakeFile name:#{name.inspect} " \
+      "parent:#{parent.to_s.inspect} size:#{content.size})"
     end
 
     def to_s
diff --git a/lib/fakefs/fake/symlink.rb b/lib/fakefs/fake/symlink.rb
index 132eead..efd3374 100644
--- a/lib/fakefs/fake/symlink.rb
+++ b/lib/fakefs/fake/symlink.rb
@@ -1,4 +1,5 @@
 module FakeFS
+  # Fake symlink class
   class FakeSymlink
     attr_accessor :name, :target, :parent
 
@@ -7,7 +8,7 @@ module FakeFS
     end
 
     def inspect
-      "symlink(#{target.split('/').last})"
+      "symlink(#{name} -> #{target.split('/').last})"
     end
 
     def entry
@@ -22,11 +23,11 @@ module FakeFS
       File.join(parent.to_s, name)
     end
 
-    def respond_to?(method)
-      entry.respond_to?(method)
+    def respond_to?(method, include_private = false)
+      entry.respond_to?(method, include_private)
     end
 
-  private
+    private
 
     def method_missing(*args, &block)
       entry.send(*args, &block)
diff --git a/lib/fakefs/file.rb b/lib/fakefs/file.rb
old mode 100644
new mode 100755
index e57cfc3..0bedeb6
--- a/lib/fakefs/file.rb
+++ b/lib/fakefs/file.rb
@@ -1,14 +1,15 @@
 require 'stringio'
 
 module FakeFS
+  # FakeFS File class inherit StringIO
   class File < StringIO
     MODES = [
-      READ_ONLY           = "r",
-      READ_WRITE          = "r+",
-      WRITE_ONLY          = "w",
-      READ_WRITE_TRUNCATE = "w+",
-      APPEND_WRITE_ONLY   = "a",
-      APPEND_READ_WRITE   = "a+"
+      READ_ONLY           = 'r',
+      READ_WRITE          = 'r+',
+      WRITE_ONLY          = 'w',
+      READ_WRITE_TRUNCATE = 'w+',
+      APPEND_WRITE_ONLY   = 'a',
+      APPEND_READ_WRITE   = 'a+'
     ]
 
     FILE_CREATION_MODES = MODES - [READ_ONLY, READ_WRITE]
@@ -35,11 +36,11 @@ module FakeFS
     end
 
     def self.exist?(path)
-      if(File.symlink?(path)) then
+      if File.symlink?(path)
         referent = File.expand_path(File.readlink(path), File.dirname(path))
         exist?(referent)
       else
-        !!FileSystem.find(path)
+        !FileSystem.find(path).nil?
       end
     end
 
@@ -49,13 +50,18 @@ module FakeFS
       # Assuming that everyone can read and write files
       alias_method :readable?, :exist?
       alias_method :writable?, :exist?
+
+      # Assume nothing is sticky.
+      def sticky?(_path)
+        false
+      end
     end
 
     def self.mtime(path)
       if exists?(path)
         FileSystem.find(path).mtime
       else
-        raise Errno::ENOENT
+        fail Errno::ENOENT
       end
     end
 
@@ -63,7 +69,7 @@ module FakeFS
       if exists?(path)
         FileSystem.find(path).ctime
       else
-        raise Errno::ENOENT
+        fail Errno::ENOENT
       end
     end
 
@@ -71,7 +77,7 @@ module FakeFS
       if exists?(path)
         FileSystem.find(path).atime
       else
-        raise Errno::ENOENT
+        fail Errno::ENOENT
       end
     end
 
@@ -81,7 +87,7 @@ module FakeFS
           FileSystem.find(path).atime = atime
           FileSystem.find(path).mtime = mtime
         else
-          raise Errno::ENOENT
+          fail Errno::ENOENT
         end
       end
 
@@ -89,15 +95,15 @@ module FakeFS
     end
 
     def self.size(path)
-      read(path).length
+      read(path).bytesize
     end
 
     def self.size?(path)
-      if exists?(path) && !size(path).zero?
-        true
-      else
-        nil
-      end
+      size(path) if exists?(path) && !size(path).zero?
+    end
+
+    def self.zero?(path)
+      exists?(path) && size(path) == 0
     end
 
     def self.const_missing(name)
@@ -130,8 +136,8 @@ module FakeFS
       end
     end
 
-    def self.expand_path(*args)
-      RealFile.expand_path(*args)
+    def self.expand_path(file_name, dir_string = FileSystem.current_dir.to_s)
+      RealFile.expand_path(file_name, RealFile.expand_path(dir_string, Dir.pwd))
     end
 
     def self.basename(*args)
@@ -148,48 +154,52 @@ module FakeFS
     end
 
     def self.read(path, *args)
+      options = args[-1].is_a?(Hash) ? args.pop : {}
+      length = args.size > 0 ? args.shift : nil
+      offset = args.size > 0 ? args.shift : 0
+      file = new(path, options)
+
+      fail Errno::ENOENT unless file.exists?
+      fail Errno::EISDIR, path if directory?(path)
+
+      FileSystem.find(path).atime = Time.now
+      file.seek(offset)
+      file.read(length)
+    end
+
+    def self.readlines(path)
       file = new(path)
       if file.exists?
         FileSystem.find(path).atime = Time.now
-        file.read
+        file.readlines
       else
-        raise Errno::ENOENT
+        fail Errno::ENOENT
       end
     end
 
-    def self.readlines(path)
-      read(path).split("\n")
-    end
-
     def self.rename(source, dest)
       if directory?(source) && file?(dest)
-        raise Errno::ENOTDIR, "Not a directory - #{source} or #{dest}"
+        fail Errno::ENOTDIR, "#{source} or #{dest}"
       elsif file?(source) && directory?(dest)
-        raise Errno::EISDIR, "Is a directory - #{source} or #{dest}"
+        fail Errno::EISDIR, "#{source} or #{dest}"
+      elsif !exist?(dirname(dest))
+        fail Errno::ENOENT, "#{source} or #{dest}"
       end
 
-      if target = FileSystem.find(source)
+      if (target = FileSystem.find(source))
         FileSystem.add(dest, target.entry.clone)
         FileSystem.delete(source)
       else
-        raise Errno::ENOENT,  "No such file or directory - #{source} or #{dest}"
+        fail Errno::ENOENT, "#{source} or #{dest}"
       end
 
       0
     end
 
     def self.link(source, dest)
-      if directory?(source)
-        raise Errno::EPERM, "Operation not permitted - #{source} or #{dest}"
-      end
-
-      if !exists?(source)
-        raise Errno::ENOENT, "No such file or directory - #{source} or #{dest}"
-      end
-
-      if exists?(dest)
-        raise Errno::EEXIST, "File exists - #{source} or #{dest}"
-      end
+      fail Errno::EPERM, "#{source} or #{dest}" if directory?(source)
+      fail Errno::ENOENT, "#{source} or #{dest}" unless exists?(source)
+      fail Errno::EEXIST, "#{source} or #{dest}" if exists?(dest)
 
       source = FileSystem.find(source)
       dest = FileSystem.add(dest, source.entry.clone)
@@ -198,18 +208,14 @@ module FakeFS
       0
     end
 
-    def self.delete(file_name, *additional_file_names)
-      if !exists?(file_name)
-        raise Errno::ENOENT, "No such file or directory - #{file_name}"
-      end
+    def self.delete(*file_names)
+      file_names.each do |file_name|
+        fail Errno::ENOENT, file_name unless exists?(file_name)
 
-      FileUtils.rm(file_name)
-
-      additional_file_names.each do |file_name|
         FileUtils.rm(file_name)
       end
 
-      additional_file_names.size + 1
+      file_names.size
     end
 
     class << self
@@ -229,46 +235,74 @@ module FakeFS
     end
 
     def self.split(path)
-      return RealFile.split(path)
+      RealFile.split(path)
     end
 
     def self.chmod(mode_int, filename)
       FileSystem.find(filename).mode = 0100000 + mode_int
     end
 
+    # Not exactly right, returns true if the file is chmod +x for owner. In the
+    # context of when you would use fakefs, this is usually what you want.
+    def self.executable?(filename)
+      file = FileSystem.find(filename)
+      return false unless file
+      (file.mode - 0100000) & 0100 != 0
+    end
+
     def self.chown(owner_int, group_int, filename)
       file = FileSystem.find(filename)
       if owner_int && owner_int != -1
-        owner_int.is_a?(Fixnum) or raise TypeError, "can't convert String into Integer"
+        owner_int.is_a?(Fixnum) || fail(TypeError,
+                                        "can't convert String into Integer")
         file.uid = owner_int
       end
       if group_int && group_int != -1
-        group_int.is_a?(Fixnum) or raise TypeError, "can't convert String into Integer"
+        group_int.is_a?(Fixnum) || fail(TypeError,
+                                        "can't convert String into Integer")
         file.gid = group_int
       end
     end
 
-    def self.umask
-      RealFile.umask
+    def self.umask(*args)
+      RealFile.umask(*args)
+    end
+
+    def self.binread(file, length = nil, offset = 0)
+      File.read(file, length, offset, mode: 'rb:ASCII-8BIT')
+    end
+
+    def self.fnmatch?(pattern, path, flags = 0)
+      RealFile.fnmatch?(pattern, path, flags)
     end
 
+    class << self
+      alias_method :fnmatch, :fnmatch?
+    end
+
+    # FakeFS Stat class
     class Stat
       attr_reader :ctime, :mtime, :atime, :mode, :uid, :gid
+      attr_reader :birthtime if RUBY_VERSION >= '2.2.0'
 
-      def initialize(file, __lstat = false)
-        if !File.exists?(file)
-          raise(Errno::ENOENT, "No such file or directory - #{file}")
-        end
+      def initialize(file, lstat = false)
+        fail(Errno::ENOENT, file) unless File.exist?(file)
 
         @file      = file
         @fake_file = FileSystem.find(@file)
-        @__lstat   = __lstat
+        @__lstat   = lstat
         @ctime     = @fake_file.ctime
         @mtime     = @fake_file.mtime
         @atime     = @fake_file.atime
         @mode      = @fake_file.mode
         @uid       = @fake_file.uid
         @gid       = @fake_file.gid
+        @birthtime =
+          if @fake_file.respond_to?(:birthtime)
+            @fake_file.birthtime
+          else
+            @fake_file.ctime
+          end
       end
 
       def symlink?
@@ -279,14 +313,40 @@ module FakeFS
         File.directory?(@file)
       end
 
-      # assumes, like above, that all files are readable and writable
+      def file?
+        File.file?(@file)
+      end
+
+      def ftype
+        return 'link' if symlink?
+        return 'directory' if directory?
+        'file'
+      end
+
+      # assumes, like above, that all files are readable and writable.
       def readable?
         true
       end
+
       def writable?
         true
       end
 
+      # Assume nothing is sticky.
+      def sticky?
+        false
+      end
+
+      # World_writable and readable are platform dependent
+      # usually comparing with S_IROTH defined on compilation (MRI)
+      def world_writable?
+        0777
+      end
+
+      def world_readable?
+        0777
+      end
+
       def nlink
         @fake_file.links.size
       end
@@ -312,7 +372,7 @@ module FakeFS
 
     attr_reader :path
 
-    def initialize(path, mode = READ_ONLY, perm = nil)
+    def initialize(path, mode = READ_ONLY, _perm = nil)
       @path = path
       @mode = mode.is_a?(Hash) ? (mode[:mode] || READ_ONLY) : mode
       @file = FileSystem.find(path)
@@ -351,12 +411,16 @@ module FakeFS
       undef_method :to_inputstream
     end
 
-    def ioctl(integer_cmd, arg)
-      raise NotImplementedError
+    def is_a?(klass)
+      RealFile.allocate.is_a?(klass)
     end
 
-    def read_nonblock(maxlen, outbuf = nil)
-      raise NotImplementedError
+    def ioctl(*)
+      fail NotImplementedError
+    end
+
+    def read_nonblock
+      fail NotImplementedError
     end
 
     def stat
@@ -378,12 +442,12 @@ module FakeFS
       self
     end
 
-    def write_nonblock(string)
-      raise NotImplementedError
+    def write_nonblock(*)
+      fail NotImplementedError
     end
 
-    def readpartial(maxlen, outbuf = nil)
-      raise NotImplementedError
+    def readpartial(*)
+      fail NotImplementedError
     end
 
     def atime
@@ -394,8 +458,8 @@ module FakeFS
       self.class.ctime(@path)
     end
 
-    def flock(locking_constant)
-      raise NotImplementedError
+    def flock(*)
+      fail NotImplementedError
     end
 
     def mtime
@@ -407,27 +471,32 @@ module FakeFS
     end
 
     def chown(owner_int, group_int)
-      if owner_int && owner_int != -1
-        owner_int.is_a?(Fixnum) or raise TypeError, "can't convert String into Integer"
-        @file.uid = owner_int
-      end
-      if group_int && group_int != -1
-        group_int.is_a?(Fixnum) or raise TypeError, "can't convert String into Integer"
-        @file.gid = group_int
-      end
+      return unless group_int && group_int != -1
+
+      owner_int.is_a?(Fixnum) || fail(
+        TypeError, "can't convert String into Integer")
+      @file.uid = owner_int
+
+      group_int.is_a?(Fixnum) || fail(
+        TypeError, "can't convert String into Integer")
+      @file.gid = group_int
     end
 
-    if RUBY_VERSION >= "1.9"
+    if RUBY_VERSION >= '1.9'
+      def self.realpath(*args)
+        RealFile.realpath(*args)
+      end
+
       def binmode?
-        raise NotImplementedError
+        fail NotImplementedError
       end
 
-      def close_on_exec=(bool)
-        raise NotImplementedError
+      def close_on_exec=(_bool)
+        fail NotImplementedError
       end
 
       def close_on_exec?
-        raise NotImplementedError
+        fail NotImplementedError
       end
 
       def to_path
@@ -435,41 +504,99 @@ module FakeFS
       end
     end
 
-    if RUBY_VERSION >= "1.9.2"
-      attr_writer :autoclose
-
-      def autoclose?
-        @autoclose
+    if RUBY_VERSION >= '1.9.1'
+      def self.absolute_path(file_name, dir_name = Dir.getwd)
+        RealFile.absolute_path(file_name, dir_name)
       end
+    end
+
+    if RUBY_VERSION >= '1.9.2'
+      attr_accessor :autoclose
 
       def autoclose?
         @autoclose ? true : false
       end
 
-      def autoclose=(autoclose)
-        @autoclose = autoclose
-      end
-
       alias_method :fdatasync, :flush
 
       def size
         File.size(@path)
       end
+
+      def self.realdirpath(*args)
+        RealFile.realdirpath(*args)
+      end
     end
 
-    if RUBY_VERSION >= "1.9.3"
-      def advise(advice, offset=0, len=0)
+    if RUBY_VERSION >= '1.9.3'
+      def advise(_advice, _offset = 0, _len = 0)
       end
+
+      def self.write(filename, contents, offset = nil, open_args = {})
+        offset, open_args = nil, offset if offset.is_a?(Hash)
+        mode = offset ? 'a' : 'w'
+        if open_args.size > 0
+          if open_args[:open_args]
+            args = [filename, *open_args[:open_args]]
+          else
+            mode = open_args[:mode] || mode
+            args = [filename, mode, open_args]
+          end
+        else
+          args = [filename, mode]
+        end
+        if offset
+          open(*args) do |f|
+            f.seek(offset)
+            f.write(contents)
+          end
+        else
+          open(*args) do |f|
+            f << contents
+          end
+        end
+
+        contents.length
+      end
+    end
+
+    if RUBY_VERSION >= '2.2.0'
+      def self.birthtime(path)
+        if exists?(path)
+          FileSystem.find(path).birthtime
+        else
+          fail Errno::ENOENT
+        end
+      end
+
+      def birthtime
+        self.class.birthtime(@path)
+      end
+    end
+
+    def read(length = nil, buf = '')
+      read_buf = super(length, buf)
+      # change to binary only for ruby 1.9.3
+      if read_buf.respond_to?(:force_encoding) && binary_mode?
+        read_buf = read_buf.force_encoding('ASCII-8BIT')
+      end
+      read_buf
     end
 
-  private
+    private
 
     def check_modes!
-      StringIO.new("", @mode)
+      StringIO.new('', @mode)
+    end
+
+    def binary_mode?
+      @mode.is_a?(String) && (@mode.include?('b') ||
+                              @mode.include?('binary')) &&
+        !@mode.include?('bom')
     end
 
     def check_file_existence!
-      raise Errno::ENOENT, @path unless @file
+      fail Errno::ENOENT, @path unless @file
     end
 
     def file_creation_mode?
@@ -477,7 +604,9 @@ module FakeFS
     end
 
     def mode_in?(list)
-      list.any? { |element| @mode.include?(element) } if @mode.respond_to?(:include?)
+      list.any? do |element|
+        @mode.include?(element)
+      end if @mode.respond_to?(:include?)
     end
 
     def mode_in_bitmask?(mask)
@@ -487,21 +616,18 @@ module FakeFS
     # Create a missing file if the path is valid.
     #
     def create_missing_file
-      raise Errno::EISDIR, "Is a directory - #{path}" if File.directory?(@path)
+      fail Errno::EISDIR, path if File.directory?(@path)
 
-      if !File.exists?(@path) # Unnecessary check, probably.
-        dirname = RealFile.dirname @path
+      return if File.exist?(@path) # Unnecessary check, probably.
+      dirname = RealFile.dirname @path
 
-        unless dirname == "."
-          dir = FileSystem.find dirname
+      unless dirname == '.'
+        dir = FileSystem.find dirname
 
-          unless dir.kind_of? FakeDir
-            raise Errno::ENOENT, "No such file or directory - #{path}"
-          end
-        end
-
-        @file = FileSystem.add(path, FakeFile.new)
+        fail Errno::ENOENT, path unless dir.is_a? FakeDir
       end
+
+      @file = FileSystem.add(path, FakeFile.new)
     end
   end
 end
diff --git a/lib/fakefs/file_system.rb b/lib/fakefs/file_system.rb
index 0e63576..df56ed0 100644
--- a/lib/fakefs/file_system.rb
+++ b/lib/fakefs/file_system.rb
@@ -1,9 +1,10 @@
 module FakeFS
+  # FileSystem module
   module FileSystem
     extend self
 
     def dir_levels
-      @dir_levels ||= []
+      @dir_levels ||= ['/']
     end
 
     def fs
@@ -32,13 +33,15 @@ module FakeFS
       end
     end
 
-    def add(path, object=FakeDir.new)
+    def add(path, object = FakeDir.new)
       parts = path_parts(normalize_path(path))
 
-      d = parts[0...-1].inject(fs) do |dir, part|
+      d = parts[0...-1].reduce(fs) do |dir, part|
+        assert_dir dir[part] if dir[part]
         dir[part] ||= FakeDir.new(part, dir)
       end
 
+      assert_dir d
       object.name = parts.last
       object.parent = d
       d[parts.last] ||= object
@@ -47,59 +50,65 @@ module FakeFS
     # copies directories and files from the real filesystem
     # into our fake one
     def clone(path, target = nil)
-      path    = File.expand_path(path)
+      path    = RealFile.expand_path(path)
       pattern = File.join(path, '**', '*')
-      files   = RealFile.file?(path) ? [path] : [path] + RealDir.glob(pattern, RealFile::FNM_DOTMATCH)
+      files   = if RealFile.file?(path)
+                  [path]
+                else
+                  [path] + RealDir.glob(pattern, RealFile::FNM_DOTMATCH)
+                end
 
       files.each do |f|
         target_path = target ? f.gsub(path, target) : f
-        if RealFile.file?(f)
+
+        if RealFile.symlink?(f)
+          FileUtils.ln_s(RealFile.readlink(f), f)
+        elsif RealFile.file?(f)
           FileUtils.mkdir_p(File.dirname(f))
           File.open(target_path, File::WRITE_ONLY) do |g|
-            g.print RealFile.open(f){|h| h.read }
+            g.print RealFile.read(f)
           end
         elsif RealFile.directory?(f)
           FileUtils.mkdir_p(target_path)
-        elsif RealFile.symlink?(f)
-          FileUtils.ln_s()
         end
       end
     end
 
     def delete(path)
-      if node = FileSystem.find(path)
-        node.delete
-        true
-      end
+      return unless (node = FileSystem.find(path))
+      node.delete
+      true
     end
 
     def chdir(dir, &blk)
       new_dir = find(dir)
       dir_levels.push dir if blk
 
-      raise Errno::ENOENT, dir unless new_dir
+      fail Errno::ENOENT, dir unless new_dir
 
-      dir_levels.push dir if !blk
+      dir_levels.push dir unless blk
       blk.call if blk
     ensure
       dir_levels.pop if blk
     end
 
     def path_parts(path)
-      drop_root(path.split(File::SEPARATOR)).reject { |part| part.empty? }
+      drop_root(path.split(File::SEPARATOR)).reject(&:empty?)
     end
 
     def normalize_path(path)
       if Pathname.new(path).absolute?
-        File.expand_path(path)
+        RealFile.expand_path(path)
       else
         parts = dir_levels + [path]
-        File.expand_path(File.join(*parts))
+        RealFile.expand_path(parts.reduce do |base, part|
+                               Pathname(base) + part
+                             end.to_s)
       end
     end
 
     def current_dir
-      find(normalize_path('.'))
+      find('.')
     end
 
     private
@@ -107,7 +116,7 @@ module FakeFS
     def drop_root(path_parts)
       # we need to remove parts from root dir at least for windows and jruby
       return path_parts if path_parts.nil? || path_parts.empty?
-      root = File.expand_path('/').split(File::SEPARATOR).first
+      root = RealFile.expand_path('/').split(File::SEPARATOR).first
       path_parts.shift if path_parts.first == root
       path_parts
     end
@@ -115,35 +124,52 @@ module FakeFS
     def find_recurser(dir, parts)
       return [] unless dir.respond_to? :[]
 
-      pattern , *parts = parts
+      pattern, *parts = parts
       matches = case pattern
-      when '**'
-        case parts
-        when ['*']
-          parts = [] # end recursion
-          directories_under(dir).map do |d|
-            d.entries.select{|f| f.is_a?(FakeFile) || f.is_a?(FakeDir) }
-          end.flatten.uniq
-        when []
-          parts = [] # end recursion
-          dir.entries.flatten.uniq
-        else
-          directories_under(dir)
-        end
-      else
-        dir.matches /\A#{pattern.gsub('.', '\.').gsub('?','.').gsub('*', '.*').gsub(/\{(.*?)\}/) { "(#{$1.gsub(',', '|')})" }}\Z/
-      end
+                when '**'
+                  case parts
+                  when ['*']
+                    parts = [] # end recursion
+                    directories_under(dir).map do |d|
+                      d.entries.select do |f|
+                        (f.is_a?(FakeFile) || f.is_a?(FakeDir)) &&
+                        f.name.match(/\A(?!\.)/)
+                      end
+                    end.flatten.uniq
+                  when []
+                    parts = [] # end recursion
+                    dir.entries.flatten.uniq
+                  else
+                    directories_under(dir)
+                  end
+                else
+                  regex_body = pattern.gsub('.', '\.')
+                               .gsub('?', '.')
+                               .gsub('*', '.*')
+                               .gsub('(', '\(')
+                               .gsub(')', '\)')
+                               .gsub(/\{(.*?)\}/) do
+                                 "(#{Regexp.last_match[1].gsub(',', '|')})"
+                               end
+                               .gsub(/\A\./, '(?!\.).')
+                  dir.matches(/\A#{regex_body}\Z/)
+                end
 
       if parts.empty? # we're done recursing
         matches
       else
-        matches.map{|entry| find_recurser(entry, parts) }
+        matches.map { |entry| find_recurser(entry, parts) }
       end
     end
 
     def directories_under(dir)
-      children = dir.entries.select{|f| f.is_a? FakeDir}
-      ([dir] + children + children.map{|c| directories_under(c)}).flatten.uniq
+      children = dir.entries.select { |f| f.is_a? FakeDir }
+      ([dir] + children + children.map { |c| directories_under(c) })
+        .flatten.uniq
+    end
+
+    def assert_dir(dir)
+      fail Errno::EEXIST, dir.name unless dir.is_a?(FakeDir)
     end
   end
 end
diff --git a/lib/fakefs/file_test.rb b/lib/fakefs/file_test.rb
index 2f6a61d..53accf3 100644
--- a/lib/fakefs/file_test.rb
+++ b/lib/fakefs/file_test.rb
@@ -1,15 +1,30 @@
 module FakeFS
-  class FileTest
-    def self.exist?(file_name)
+  # FileTest
+  module FileTest
+    extend self
+
+    def exist?(file_name)
       File.exist?(file_name)
     end
 
-    def self.directory?(file_name)
+    def directory?(file_name)
       File.directory?(file_name)
     end
 
-    def self.file?(file_name)
+    def file?(file_name)
       File.file?(file_name)
     end
+
+    def size?(file_name)
+      File.size?(file_name)
+    end
+
+    def readable?(file_name)
+      File.readable?(file_name)
+    end
+
+    def writable?(file_name)
+      File.writable?(file_name)
+    end
   end
 end
diff --git a/lib/fakefs/fileutils.rb b/lib/fakefs/fileutils.rb
index 2c1ba0e..3fb4bce 100644
--- a/lib/fakefs/fileutils.rb
+++ b/lib/fakefs/fileutils.rb
@@ -1,107 +1,155 @@
 module FakeFS
+  # FileUtils module
   module FileUtils
     extend self
 
-    def mkdir_p(path, options = {})
-      FileSystem.add(path, FakeDir.new)
+    def mkdir_p(list, options = {})
+      list = [list] unless list.is_a?(Array)
+      list.each do |path|
+        # FileSystem.add call adds all the necessary parent directories but
+        # can't set their mode. Thus, we have to collect created directories
+        # here and set the mode later.
+        if options[:mode]
+          created_dirs = []
+          dir = path
+
+          until Dir.exist?(dir)
+            created_dirs << dir
+            dir = File.dirname(dir)
+          end
+        end
+
+        FileSystem.add(path, FakeDir.new)
+
+        next unless options[:mode]
+        created_dirs.each do |d|
+          File.chmod(options[:mode], d)
+        end
+      end
     end
+
     alias_method :mkpath, :mkdir_p
     alias_method :makedirs, :mkdir_p
 
-    def mkdir(path)
-      parent = path.split('/')
-      parent.pop
-      raise Errno::ENOENT, "No such file or directory - #{path}" unless parent.join == "" || parent.join == "." || FileSystem.find(parent.join('/'))
-      raise Errno::EEXIST, "File exists - #{path}" if FileSystem.find(path)
-      FileSystem.add(path, FakeDir.new)
+    def mkdir(list, _ignored_options = {})
+      list = [list] unless list.is_a?(Array)
+      list.each do |path|
+        parent = path.split('/')
+        parent.pop
+        fail Errno::ENOENT, path unless parent.join == '' ||
+                                        parent.join == '.' ||
+                                        FileSystem.find(parent.join('/'))
+        fail Errno::EEXIST, path if FileSystem.find(path)
+        FileSystem.add(path, FakeDir.new)
+      end
     end
 
-    def rmdir(list, options = {})
-      list = [ list ] unless list.is_a?(Array)
+    def rmdir(list, _options = {})
+      list = [list] unless list.is_a?(Array)
       list.each do |l|
         parent = l.split('/')
         parent.pop
-        raise Errno::ENOENT, "No such file or directory - #{l}" unless parent.join == "" || FileSystem.find(parent.join('/'))
-        raise Errno::ENOENT, l unless FileSystem.find(l)
-        raise Errno::ENOTEMPTY, l unless FileSystem.find(l).empty?
+        fail Errno::ENOENT, l unless parent.join == '' ||
+                                     FileSystem.find(parent.join('/'))
+        fail Errno::ENOENT, l unless FileSystem.find(l)
+        fail Errno::ENOTEMPTY, l unless FileSystem.find(l).empty?
         rm(l)
       end
     end
 
     def rm(list, options = {})
       Array(list).each do |path|
-        FileSystem.delete(path) or (!options[:force] && raise(Errno::ENOENT.new(path)))
+        FileSystem.delete(path) ||
+          (!options[:force] && fail(Errno::ENOENT, path))
       end
     end
-
-    alias_method :rm_rf, :rm
     alias_method :rm_r, :rm
     alias_method :rm_f, :rm
+    alias_method :remove, :rm
+
+    def rm_rf(list, options = {})
+      rm_r(list, options.merge(force: true))
+    end
+    alias_method :rmtree, :rm_rf
+    alias_method :safe_unlink, :rm_f
+    alias_method :remove_entry_secure, :rm_rf
 
     def ln_s(target, path, options = {})
-      options = { :force => false }.merge(options)
-      (FileSystem.find(path) && !options[:force]) ?
-        raise(Errno::EEXIST, path) :
-        FileSystem.delete(path)
+      options = { force: false }.merge(options)
+      fail(Errno::EEXIST, path) if FileSystem.find(path) && !options[:force]
+      FileSystem.delete(path)
 
-      if !options[:force] && !Dir.exists?(File.dirname(path))
-        raise Errno::ENOENT, path
+      if !options[:force] && !Dir.exist?(File.dirname(path))
+        fail Errno::ENOENT, path
       end
 
       FileSystem.add(path, FakeSymlink.new(target))
     end
 
     def ln_sf(target, path)
-      ln_s(target, path, { :force => true })
+      ln_s(target, path, force: true)
     end
 
-    def cp(src, dest)
-      if src.is_a?(Array) && !File.directory?(dest)
-        raise Errno::ENOTDIR, dest
-      end
+    alias_method :symlink, :ln_s
 
-      Array(src).each do |src|
-        dst_file = FileSystem.find(dest)
-        src_file = FileSystem.find(src)
+    def cp(src, dest, options = {})
+      fail Errno::ENOTDIR, dest if src.is_a?(Array) && !File.directory?(dest)
 
-        if !src_file
-          raise Errno::ENOENT, src
-        end
+      # handle `verbose' flag
+      RealFileUtils.cp src, dest, options.merge(noop: true)
 
-        if File.directory? src_file
-          raise Errno::EISDIR, src
-        end
+      # handle `noop' flag
+      return if options[:noop]
+
+      Array(src).each do |source|
+        dst_file = FileSystem.find(dest)
+        src_file = FileSystem.find(source)
+
+        fail Errno::ENOENT, source unless src_file
+        fail Errno::EISDIR, source if File.directory? src_file
 
         if dst_file && File.directory?(dst_file)
-          FileSystem.add(File.join(dest, src), src_file.entry.clone(dst_file))
+          FileSystem.add(
+            File.join(
+              dest, File.basename(source)), src_file.entry.clone(dst_file))
         else
           FileSystem.delete(dest)
           FileSystem.add(dest, src_file.entry.clone)
         end
       end
+
+      nil
     end
 
-    def cp_r(src, dest)
-      Array(src).each do |src|
+    alias_method :copy, :cp
+
+    def copy_file(src, dest, _preserve = false, _dereference = true)
+      # Not a perfect match, but similar to what regular FileUtils does.
+      cp(src, dest)
+    end
+
+    def cp_r(src, dest, options = {})
+      # handle `verbose' flag
+      RealFileUtils.cp_r src, dest, options.merge(noop: true)
+
+      # handle `noop' flag
+      return if options[:noop]
+
+      Array(src).each do |source|
         # This error sucks, but it conforms to the original Ruby
         # method.
-        raise "unknown file type: #{src}" unless dir = FileSystem.find(src)
-
+        fail "unknown file type: #{source}" unless
+          (dir = FileSystem.find(source))
         new_dir = FileSystem.find(dest)
 
-        if new_dir && !File.directory?(dest)
-          raise Errno::EEXIST, dest
-        end
-
-        if !new_dir && !FileSystem.find(dest+'/../')
-          raise Errno::ENOENT, dest
-        end
+        fail Errno::EEXIST, dest if new_dir && !File.directory?(dest)
+        fail Errno::ENOENT, dest if !new_dir && !FileSystem.find(dest + '/../')
 
         # This last bit is a total abuse and should be thought hard
         # about and cleaned up.
         if new_dir
           if src[-2..-1] == '/.'
-            dir.entries.each{|f| new_dir[f.name] = f.clone(new_dir) }
+            dir.entries.each { |f| new_dir[f.name] = f.clone(new_dir) }
           else
             new_dir[dir.name] = dir.entry.clone(new_dir)
           end
@@ -109,44 +157,64 @@ module FakeFS
           FileSystem.add(dest, dir.entry.clone)
         end
       end
+
+      nil
     end
 
-    def mv(src, dest, options={})
+    def mv(src, dest, options = {})
+      # handle `verbose' flag
+      RealFileUtils.mv src, dest, options.merge(noop: true)
+
+      # handle `noop' flag
+      return if options[:noop]
+
       Array(src).each do |path|
-        if target = FileSystem.find(path)
-          dest_path = File.directory?(dest) ? File.join(dest, File.basename(path)) : dest
-          FileSystem.delete(dest_path)
-          FileSystem.add(dest_path, target.entry.clone)
-          FileSystem.delete(path)
+        if (target = FileSystem.find(path))
+          dest_path = if File.directory?(dest)
+                        File.join(dest, File.basename(path))
+                      else
+                        dest
+                      end
+          if File.directory?(dest_path)
+            fail Errno::EEXIST, dest_path unless options[:force]
+          elsif File.directory?(File.dirname(dest_path))
+            FileSystem.delete(dest_path)
+            FileSystem.add(dest_path, target.entry.clone)
+            FileSystem.delete(path)
+          else
+            fail Errno::ENOENT, dest_path unless options[:force]
+          end
         else
-          raise Errno::ENOENT, path
+          fail Errno::ENOENT, path
         end
       end
+
+      nil
     end
 
-    def chown(user, group, list, options={})
+    alias_method :move, :mv
+
+    def chown(user, group, list, _options = {})
       list = Array(list)
       list.each do |f|
-        if File.exists?(f)
+        if File.exist?(f)
           uid = if user
-                  user.to_s.match(/[0-9]+/) ? user.to_i : Etc.getpwnam(user).uid
-                else
-                  nil
+                  user.to_s.match(/[0-9]+/) ? user.to_i :
+                    Etc.getpwnam(user).uid
                 end
           gid = if group
-                  group.to_s.match(/[0-9]+/) ? group.to_i : Etc.getgrnam(group).gid
-                else
-                  nil
+                  group.to_s.match(/[0-9]+/) ? group.to_i :
+                    Etc.getgrnam(group).gid
                 end
           File.chown(uid, gid, f)
         else
-          raise Errno::ENOENT, f
+          fail Errno::ENOENT, f
         end
       end
       list
     end
 
-    def chown_R(user, group, list, options={})
+    def chown_R(user, group, list, _options = {})
       list = Array(list)
       list.each do |file|
         chown(user, group, file)
@@ -157,19 +225,19 @@ module FakeFS
       list
     end
 
-    def chmod(mode, list, options={})
+    def chmod(mode, list, _options = {})
       list = Array(list)
       list.each do |f|
-        if File.exists?(f)
+        if File.exist?(f)
           File.chmod(mode, f)
         else
-          raise Errno::ENOENT, f
+          fail Errno::ENOENT, f
         end
       end
       list
     end
 
-    def chmod_R(mode, list, options={})
+    def chmod_R(mode, list, _options = {})
       list = Array(list)
       list.each do |file|
         chmod(mode, file)
@@ -180,22 +248,35 @@ module FakeFS
       list
     end
 
-    def touch(list, options={})
+    def touch(list, options = {})
       Array(list).each do |f|
-        if fs = FileSystem.find(f)
+        if (fs = FileSystem.find(f))
           now = Time.now
-          fs.mtime = now
+          fs.mtime = options[:mtime] || now
           fs.atime = now
         else
-          f = File.open(f, 'w')
-          f.close
+          file = File.open(f, 'w')
+          file.close
+
+          if (mtime = options[:mtime])
+            fs = FileSystem.find(f)
+            fs.mtime = mtime
+          end
         end
       end
     end
 
-    def cd(dir)
-      FileSystem.chdir(dir)
+    def cd(dir, &block)
+      FileSystem.chdir(dir, &block)
     end
     alias_method :chdir, :cd
+
+    def compare_file(file1, file2)
+      # we do a strict comparison of both files content
+      File.readlines(file1) == File.readlines(file2)
+    end
+
+    alias_method :cmp, :compare_file
+    alias_method :identical?, :compare_file
   end
 end
diff --git a/lib/fakefs/kernel.rb b/lib/fakefs/kernel.rb
new file mode 100644
index 0000000..5bb5493
--- /dev/null
+++ b/lib/fakefs/kernel.rb
@@ -0,0 +1,43 @@
+module FakeFS
+  # Kernel Module
+  module Kernel
+    @captives = { original: {}, hijacked: {} }
+
+    class << self
+      attr_accessor :captives
+    end
+
+    def self.hijack!
+      captives[:hijacked].each do |name, prc|
+        ::Kernel.send(:remove_method, name.to_sym)
+        ::Kernel.send(:define_method, name.to_sym, &prc)
+      end
+    end
+
+    def self.unhijack!
+      captives[:original].each do |name, _prc|
+        ::Kernel.send(:remove_method, name.to_sym)
+        ::Kernel.send(:define_method, name.to_sym, proc do |*args, &block|
+          ::FakeFS::Kernel.captives[:original][name].call(*args, &block)
+        end)
+      end
+    end
+
+    private
+
+    def self.hijack(name, &block)
+      captives[:original][name] = ::Kernel.method(name.to_sym)
+      captives[:hijacked][name] = block || proc { |_args| }
+    end
+
+    hijack :open do |*args, &block|
+      if args.first.start_with? '|'
+        # This is a system command
+        ::FakeFS::Kernel.captives[:original][:open].call(*args, &block)
+      else
+        name = args.shift
+        FakeFS::File.open(name, *args, &block)
+      end
+    end
+  end
+end
diff --git a/lib/fakefs/pathname.rb b/lib/fakefs/pathname.rb
index 181af36..9bd8ebc 100644
--- a/lib/fakefs/pathname.rb
+++ b/lib/fakefs/pathname.rb
@@ -1,6 +1,7 @@
+# FakeFS module
 module FakeFS
-  if RUBY_VERSION >= "1.9.3"
-  
+  if RUBY_VERSION >= '1.9.3'
+
     #
     # = pathname.rb - From MRI 1.9.2
     #
@@ -12,52 +13,68 @@ module FakeFS
     # For documentation, see class Pathname.
     #
     class Pathname
-
-      # to_path is implemented so Pathname objects are usable with File.open, etc.
+      # to_path is implemented so Pathname objects are
+      # usable with File.open, etc.
       TO_PATH = :to_path
 
       SAME_PATHS = if File::FNM_SYSCASE.nonzero?
-        proc {|a, b| a.casecmp(b).zero?}
-      else
-        proc {|a, b| a == b}
-      end
+                     proc { |a, b| a.casecmp(b).zero? }
+                   else
+                     proc { |a, b| a == b }
+                   end
 
       # :startdoc:
 
       #
       # Create a Pathname object from the given String (or String-like object).
-      # If +path+ contains a NUL character (<tt>\0</tt>), an ArgumentError is raised.
+      # If +path+ contains a NUL character (<tt>\0</tt>),
+      # an ArgumentError is raised.
       #
       def initialize(path)
         path = path.__send__(TO_PATH) if path.respond_to? TO_PATH
         @path = path.dup
 
         if /\0/ =~ @path
-          raise ArgumentError, "pathname contains \\0: #{@path.inspect}"
+          fail ArgumentError, "pathname contains \\0: #{@path.inspect}"
         end
 
-        self.taint if @path.tainted?
+        taint if @path.tainted?
+      end
+
+      def freeze
+        super
+        @path.freeze
+        self
       end
 
-      def freeze() super; @path.freeze; self end
-      def taint() super; @path.taint; self end
-      def untaint() super; @path.untaint; self end
+      def taint
+        super
+        @path.taint
+        self
+      end
+
+      def untaint
+        super
+        @path.untaint
+        self
+      end
 
       #
       # Compare this pathname with +other+.  The comparison is string-based.
-      # Be aware that two different paths (<tt>foo.txt</tt> and <tt>./foo.txt</tt>)
-      # can refer to the same file.
+      # Be aware that two different paths
+      # (<tt>foo.txt</tt> and <tt>./foo.txt</tt>) can refer to the same file.
       #
       def ==(other)
-        return false unless Pathname === other
+        return false unless other.is_a?(Pathname)
         other.to_s == @path
       end
-      alias === ==
-      alias eql? ==
+
+      alias_method :===, :==
+      alias_method :eql?, :==
 
       # Provides for comparing pathnames, case-sensitively.
       def <=>(other)
-        return nil unless Pathname === other
+        return nil unless other.is_a?(Pathname)
         @path.tr('/', "\0") <=> other.to_s.tr('/', "\0")
       end
 
@@ -70,7 +87,8 @@ module FakeFS
         @path.dup
       end
 
-      # to_path is implemented so Pathname objects are usable with File.open, etc.
+      # to_path is implemented so Pathname objects are usable
+      # with File.open, etc.
       alias_method TO_PATH, :to_s
 
       def inspect # :nodoc:
@@ -80,16 +98,17 @@ module FakeFS
       # Return a pathname which is substituted by String#sub.
       def sub(pattern, *rest, &block)
         if block
-          path = @path.sub(pattern, *rest) {|*args|
+          path = @path.sub(pattern, *rest) do |*args|
             begin
               old = Thread.current[:pathname_sub_matchdata]
-              Thread.current[:pathname_sub_matchdata] = $~
-              eval("$~ = Thread.current[:pathname_sub_matchdata]", block.binding)
+              Thread.current[:pathname_sub_matchdata] = $LAST_MATCH_INFO
+              eval('$~ = Thread.current[:pathname_sub_matchdata]',
+                   block.binding)
             ensure
               Thread.current[:pathname_sub_matchdata] = old
             end
             yield(*args)
-          }
+          end
         else
           path = @path.sub(pattern, *rest)
         end
@@ -97,7 +116,8 @@ module FakeFS
       end
 
       if File::ALT_SEPARATOR
-        SEPARATOR_LIST = "#{Regexp.quote File::ALT_SEPARATOR}#{Regexp.quote File::SEPARATOR}"
+        SEPARATOR_LIST = "#{Regexp.quote File::ALT_SEPARATOR}" \
+        "#{Regexp.quote File::SEPARATOR}"
         SEPARATOR_PAT = /[#{SEPARATOR_LIST}]/
       else
         SEPARATOR_LIST = "#{Regexp.quote File::SEPARATOR}"
@@ -127,12 +147,14 @@ module FakeFS
       # split_names(path) -> prefix, [name, ...]
       def split_names(path)
         names = []
-        while r = chop_basename(path)
+        while (r = chop_basename(path))
           path, basename = r
           names.unshift basename
         end
-        return path, names
+
+        [path, names]
       end
+
       private :split_names
 
       def prepend_prefix(prefix, relpath)
@@ -140,7 +162,7 @@ module FakeFS
           File.dirname(prefix)
         elsif /#{SEPARATOR_PAT}/o =~ prefix
           prefix = File.dirname(prefix)
-          prefix = File.join(prefix, "") if File.basename(prefix + 'a') != 'a'
+          prefix = File.join(prefix, '') if File.basename(prefix + 'a') != 'a'
           prefix + relpath
         else
           prefix + relpath
@@ -148,15 +170,16 @@ module FakeFS
       end
       private :prepend_prefix
 
-      # Returns clean pathname of +self+ with consecutive slashes and useless dots
-      # removed.  The filesystem is not accessed.
+      # Returns clean pathname of +self+ with consecutive slashes and
+      # useless dots removed. The filesystem is not accessed.
       #
-      # If +consider_symlink+ is +true+, then a more conservative algorithm is used
-      # to avoid breaking symbolic linkages.  This may retain more <tt>..</tt>
-      # entries than absolutely necessary, but without accessing the filesystem,
-      # this can't be avoided.  See #realpath.
+      # If +consider_symlink+ is +true+, then a more conservative algorithm
+      # is used to avoid breaking symbolic linkages.
+      # This may retain more <tt>..</tt> entries than absolutely necessary,
+      # but without accessing the filesystem, this can't be avoided.
+      # See #realpath.
       #
-      def cleanpath(consider_symlink=false)
+      def cleanpath(consider_symlink = false)
         if consider_symlink
           cleanpath_conservative
         else
@@ -165,14 +188,15 @@ module FakeFS
       end
 
       #
-      # Clean the path simply by resolving and removing excess "." and ".." entries.
+      # Clean the path simply by resolving and removing excess
+      # "." and ".." entries.
       # Nothing more, nothing less.
       #
       def cleanpath_aggressive
         path = @path
         names = []
         pre = path
-        while r = chop_basename(pre)
+        while (r = chop_basename(pre))
           pre, base = r
           case base
           when '.'
@@ -193,29 +217,31 @@ module FakeFS
       end
       private :cleanpath_aggressive
 
-      # has_trailing_separator?(path) -> bool
-      def has_trailing_separator?(path)
-        if r = chop_basename(path)
+      # trailing_separator?(path) -> bool
+      def trailing_separator?(path)
+        if (r = chop_basename(path))
           pre, basename = r
           pre.length + basename.length < path.length
         else
           false
         end
       end
-      private :has_trailing_separator?
+
+      private :trailing_separator?
 
       # add_trailing_separator(path) -> path
       def add_trailing_separator(path)
         if File.basename(path + 'a') == 'a'
           path
         else
-          File.join(path, "") # xxx: Is File.join is appropriate to add separator?
+          # xxx: Is File.join is appropriate to add separator?
+          File.join(path, '')
         end
       end
       private :add_trailing_separator
 
       def del_trailing_separator(path)
-        if r = chop_basename(path)
+        if (r = chop_basename(path))
           pre, basename = r
           pre + basename
         elsif /#{SEPARATOR_PAT}+\z/o =~ path
@@ -230,7 +256,7 @@ module FakeFS
         path = @path
         names = []
         pre = path
-        while r = chop_basename(pre)
+        while (r = chop_basename(pre))
           pre, base = r
           names.unshift base if base != '.'
         end
@@ -240,11 +266,10 @@ module FakeFS
         if names.empty?
           self.class.new(File.dirname(pre))
         else
-          if names.last != '..' && File.basename(path) == '.'
-            names << '.'
-          end
+          names << '.' if names.last != '..' && File.basename(path) == '.'
+
           result = prepend_prefix(pre, File.join(*names))
-          if /\A(?:\.|\.\.)\z/ !~ names.last && has_trailing_separator?(path)
+          if /\A(?:\.|\.\.)\z/ !~ names.last && trailing_separator?(path)
             self.class.new(add_trailing_separator(result))
           else
             self.class.new(result)
@@ -260,7 +285,7 @@ module FakeFS
       # All components of the pathname must exist when this method is
       # called.
       #
-      def realpath(basedir=nil)
+      def realpath(basedir = nil)
         self.class.new(File.realpath(@path, basedir))
       end
 
@@ -270,7 +295,7 @@ module FakeFS
       #
       # The last component of the real pathname can be nonexistent.
       #
-      def realdirpath(basedir=nil)
+      def realdirpath(basedir = nil)
         self.class.new(File.realdirpath(@path, basedir))
       end
 
@@ -283,9 +308,9 @@ module FakeFS
 
       # #mountpoint? returns +true+ if <tt>self</tt> points to a mountpoint.
       def mountpoint?
+        stat1 = lstat
         begin
-          stat1 = self.lstat
-          stat2 = self.parent.lstat
+          stat2 = parent.lstat
           stat1.dev == stat2.dev && stat1.ino == stat2.ino ||
             stat1.dev != stat2.dev
         rescue Errno::ENOENT
@@ -294,14 +319,15 @@ module FakeFS
       end
 
       #
-      # #root? is a predicate for root directories.  I.e. it returns +true+ if the
+      # #root? is a predicate for root directories.
+      # I.e. it returns +true+ if the
       # pathname consists of consecutive slashes.
       #
       # It doesn't access actual filesystem.  So it may return +false+ for some
       # pathnames which points to roots such as <tt>/usr/..</tt>.
       #
       def root?
-        !!(chop_basename(@path) == nil && /#{SEPARATOR_PAT}/o =~ @path)
+        !(chop_basename(@path).nil? && /#{SEPARATOR_PAT}/o =~ @path).nil?
       end
 
       # Predicate method for testing whether a path is absolute.
@@ -313,8 +339,8 @@ module FakeFS
       # The opposite of #absolute?
       def relative?
         path = @path
-        while r = chop_basename(path)
-          path, basename = r
+        while (r = chop_basename(path))
+          path, _basename = r
         end
         path == ''
       end
@@ -322,27 +348,27 @@ module FakeFS
       #
       # Iterates over each component of the path.
       #
-      #   Pathname.new("/usr/bin/ruby").each_filename {|filename| ... }
+      #   Pathname.new("/usr/bin/ruby").each_filename { |filename| ... }
       #     # yields "usr", "bin", and "ruby".
       #
       def each_filename # :yield: filename
         return to_enum(__method__) unless block_given?
-        prefix, names = split_names(@path)
-        names.each {|filename| yield filename }
+        _prefix, names = split_names(@path)
+        names.each { |filename| yield filename }
         nil
       end
 
       # Iterates over and yields a new Pathname object
       # for each element in the given path in descending order.
       #
-      #  Pathname.new('/path/to/some/file.rb').descend {|v| p v}
+      #  Pathname.new('/path/to/some/file.rb').descend { |v| p v}
       #     #<Pathname:/>
       #     #<Pathname:/path>
       #     #<Pathname:/path/to>
       #     #<Pathname:/path/to/some>
       #     #<Pathname:/path/to/some/file.rb>
       #
-      #  Pathname.new('path/to/some/file.rb').descend {|v| p v}
+      #  Pathname.new('path/to/some/file.rb').descend { |v| p v}
       #     #<Pathname:path>
       #     #<Pathname:path/to>
       #     #<Pathname:path/to/some>
@@ -354,22 +380,22 @@ module FakeFS
       #
       def descend
         vs = []
-        ascend {|v| vs << v }
-        vs.reverse_each {|v| yield v }
+        ascend { |v| vs << v }
+        vs.reverse_each { |v| yield v }
         nil
       end
 
       # Iterates over and yields a new Pathname object
       # for each element in the given path in ascending order.
       #
-      #  Pathname.new('/path/to/some/file.rb').ascend {|v| p v}
+      #  Pathname.new('/path/to/some/file.rb').ascend { |v| p v}
       #     #<Pathname:/path/to/some/file.rb>
       #     #<Pathname:/path/to/some>
       #     #<Pathname:/path/to>
       #     #<Pathname:/path>
       #     #<Pathname:/>
       #
-      #  Pathname.new('path/to/some/file.rb').ascend {|v| p v}
+      #  Pathname.new('path/to/some/file.rb').ascend { |v| p v}
       #     #<Pathname:path/to/some/file.rb>
       #     #<Pathname:path/to/some>
       #     #<Pathname:path/to>
@@ -382,25 +408,27 @@ module FakeFS
       def ascend
         path = @path
         yield self
-        while r = chop_basename(path)
-          path, name = r
+        while (r = chop_basename(path))
+          path, _name = r
           break if path.empty?
           yield self.class.new(del_trailing_separator(path))
         end
       end
 
       #
-      # Pathname#+ appends a pathname fragment to this one to produce a new Pathname
+      # Pathname#+ appends a pathname fragment to this one to produce a new
+      # Pathname
       # object.
       #
       #   p1 = Pathname.new("/usr")      # Pathname:/usr
       #   p2 = p1 + "bin/ruby"           # Pathname:/usr/bin/ruby
       #   p3 = p1 + "/etc/passwd"        # Pathname:/etc/passwd
       #
-      # This method doesn't access the file system; it is pure string manipulation.
+      # This method doesn't access the file system; it is pure string
+      # manipulation.
       #
       def +(other)
-        other = Pathname.new(other) unless Pathname === other
+        other = Pathname.new(other) unless other.is_a?(Pathname)
         Pathname.new(plus(@path, other.to_s))
       end
 
@@ -408,28 +436,33 @@ module FakeFS
         prefix2 = path2
         index_list2 = []
         basename_list2 = []
-        while r2 = chop_basename(prefix2)
+        while (r2 = chop_basename(prefix2))
           prefix2, basename2 = r2
           index_list2.unshift prefix2.length
           basename_list2.unshift basename2
         end
+
         return path2 if prefix2 != ''
+
         prefix1 = path1
-        while true
+        while (r1 = chop_basename(prefix1))
           while !basename_list2.empty? && basename_list2.first == '.'
             index_list2.shift
             basename_list2.shift
           end
-          break unless r1 = chop_basename(prefix1)
+
           prefix1, basename1 = r1
           next if basename1 == '.'
-          if basename1 == '..' || basename_list2.empty? || basename_list2.first != '..'
-            prefix1 = prefix1 + basename1
+          if basename1 == '..' ||
+             basename_list2.empty? ||
+             basename_list2.first != '..'
+            prefix1 += basename1
             break
           end
           index_list2.shift
           basename_list2.shift
         end
+
         r1 = chop_basename(prefix1)
         if !r1 && /#{SEPARATOR_PAT}/o =~ File.basename(prefix1)
           while !basename_list2.empty? && basename_list2.first == '..'
@@ -437,6 +470,7 @@ module FakeFS
             basename_list2.shift
           end
         end
+
         if !basename_list2.empty?
           suffix2 = path2[index_list2.first..-1]
           r1 ? File.join(prefix1, suffix2) : prefix1 + suffix2
@@ -455,13 +489,13 @@ module FakeFS
       def join(*args)
         args.unshift self
         result = args.pop
-        result = Pathname.new(result) unless Pathname === result
+        result = Pathname.new(result) unless result.is_a?(Pathname)
         return result if result.absolute?
-        args.reverse_each {|arg|
-          arg = Pathname.new(arg) unless Pathname === arg
+        args.reverse_each do |arg|
+          arg = Pathname.new(arg) unless arg.is_a?(Pathname)
           result = arg + result
           return result if result.absolute?
-        }
+        end
         result
       end
 
@@ -469,44 +503,50 @@ module FakeFS
       # Returns the children of the directory (files and subdirectories, not
       # recursive) as an array of Pathname objects.  By default, the returned
       # pathnames will have enough information to access the files.  If you set
-      # +with_directory+ to +false+, then the returned pathnames will contain the
+      # +with_directory+ to +false+, then the returned
+      # pathnames will contain the
       # filename only.
       #
       # For example:
       #   pn = Pathname("/usr/lib/ruby/1.8")
       #   pn.children
-      #       # -> [ Pathname:/usr/lib/ruby/1.8/English.rb,
-      #              Pathname:/usr/lib/ruby/1.8/Env.rb,
-      #              Pathname:/usr/lib/ruby/1.8/abbrev.rb, ... ]
+      #     # -> [ Pathname:/usr/lib/ruby/1.8/English.rb,
+      #            Pathname:/usr/lib/ruby/1.8/Env.rb,
+      #            Pathname:/usr/lib/ruby/1.8/abbrev.rb, ... ]
       #   pn.children(false)
-      #       # -> [ Pathname:English.rb, Pathname:Env.rb, Pathname:abbrev.rb, ... ]
+      #     # -> [ Pathname:English.rb,
+      #            Pathname:Env.rb,
+      #            Pathname:abbrev.rb, ... ]
       #
-      # Note that the result never contain the entries <tt>.</tt> and <tt>..</tt> in
+      # Note that the result never contain the entries
+      # <tt>.</tt> and <tt>..</tt> in
       # the directory because they are not children.
       #
       # This method has existed since 1.8.1.
       #
-      def children(with_directory=true)
+      def children(with_directory = true)
         with_directory = false if @path == '.'
         result = []
-        Dir.foreach(@path) {|e|
+        Dir.foreach(@path) do |e|
           next if e == '.' || e == '..'
           if with_directory
             result << self.class.new(File.join(@path, e))
           else
             result << self.class.new(e)
           end
-        }
+        end
         result
       end
 
       # Iterates over the children of the directory
       # (files and subdirectories, not recursive).
       # It yields Pathname object for each child.
-      # By default, the yielded pathnames will have enough information to access the files.
-      # If you set +with_directory+ to +false+, then the returned pathnames will contain the filename only.
+      # By default, the yielded pathnames will have enough information to access
+      # the files.
+      # If you set +with_directory+ to +false+,
+      # then the returned pathnames will contain the filename only.
       #
-      #   Pathname("/usr/local").each_child {|f| p f }
+      #   Pathname("/usr/local").each_child { |f| p f }
       #   #=> #<Pathname:/usr/local/share>
       #   #   #<Pathname:/usr/local/bin>
       #   #   #<Pathname:/usr/local/games>
@@ -516,7 +556,7 @@ module FakeFS
       #   #   #<Pathname:/usr/local/src>
       #   #   #<Pathname:/usr/local/man>
       #
-      #   Pathname("/usr/local").each_child(false) {|f| p f }
+      #   Pathname("/usr/local").each_child(false) { |f| p f }
       #   #=> #<Pathname:share>
       #   #   #<Pathname:bin>
       #   #   #<Pathname:games>
@@ -526,38 +566,40 @@ module FakeFS
       #   #   #<Pathname:src>
       #   #   #<Pathname:man>
       #
-      def each_child(with_directory=true, &b)
+      def each_child(with_directory = true, &b)
         children(with_directory).each(&b)
       end
 
       #
       # #relative_path_from returns a relative path from the argument to the
-      # receiver.  If +self+ is absolute, the argument must be absolute too.  If
+      # receiver.  If +self+ is absolute, the argument must be absolute too. If
       # +self+ is relative, the argument must be relative too.
       #
-      # #relative_path_from doesn't access the filesystem.  It assumes no symlinks.
+      # #relative_path_from doesn't access the filesystem.
+      # It assumes no symlinks.
       #
       # ArgumentError is raised when it cannot find a relative path.
       #
       # This method has existed since 1.8.1.
       #
       def relative_path_from(base_directory)
-        dest_directory = self.cleanpath.to_s
+        dest_directory = cleanpath.to_s
         base_directory = base_directory.cleanpath.to_s
         dest_prefix = dest_directory
         dest_names = []
-        while r = chop_basename(dest_prefix)
+        while (r = chop_basename(dest_prefix))
           dest_prefix, basename = r
           dest_names.unshift basename if basename != '.'
         end
         base_prefix = base_directory
         base_names = []
-        while r = chop_basename(base_prefix)
+        while (r = chop_basename(base_prefix))
           base_prefix, basename = r
           base_names.unshift basename if basename != '.'
         end
         unless SAME_PATHS[dest_prefix, base_prefix]
-          raise ArgumentError, "different prefix: #{dest_prefix.inspect} and #{base_directory.inspect}"
+          fail ArgumentError, "different prefix: #{dest_prefix.inspect} " \
+          "and #{base_directory.inspect}"
         end
         while !dest_names.empty? &&
               !base_names.empty? &&
@@ -566,7 +608,7 @@ module FakeFS
           base_names.shift
         end
         if base_names.include? '..'
-          raise ArgumentError, "base_directory has ..: #{base_directory.inspect}"
+          fail ArgumentError, "base_directory has ..: #{base_directory.inspect}"
         end
         base_names.fill('..')
         relpath_names = base_names + dest_names
@@ -578,69 +620,106 @@ module FakeFS
       end
     end
 
+    # Pathname class
     class Pathname    # * IO *
       #
-      # #each_line iterates over the line in the file.  It yields a String object
-      # for each line.
+      # #each_line iterates over the line in the file.
+      # It yields a String object for each line.
       #
       # This method has existed since 1.8.1.
       #
       def each_line(*args, &block) # :yield: line
-        IO.foreach(@path, *args, &block)
+        if block_given?
+          File.open(@path, 'r') do |io|
+            io.each_line(*args, &block)
+          end
+        else
+          enum_for(:each_line, *args)
+        end
       end
 
-      # See <tt>IO.read</tt>.  Returns all data from the file, or the first +N+ bytes
-      # if specified.
-      def read(*args) IO.read(@path, *args) end
+      # See <tt>IO.read</tt>. Returns all data from the file,
+      # or the first +N+ bytes if specified.
+      def read(*args)
+        File.read(@path, *args)
+      end
 
-      # See <tt>IO.binread</tt>.  Returns all the bytes from the file, or the first +N+
-      # if specified.
-      def binread(*args) IO.binread(@path, *args) end
+      # See <tt>IO.binread</tt>.  Returns all the bytes from the file,
+      # or the first +N+ if specified.
+      def binread(*args)
+        File.binread(@path, *args)
+      end
 
       # See <tt>IO.readlines</tt>.  Returns all the lines from the file.
-      def readlines(*args) IO.readlines(@path, *args) end
+      def readlines(*args)
+        File.readlines(@path, *args)
+      end
 
-      # See <tt>IO.sysopen</tt>.
-      def sysopen(*args) IO.sysopen(@path, *args) end
+      # See <tt>IO.sysopen</tt>. Not supported by fakefs.
+      def sysopen(*_args)
+        fail NotImplementedError, 'sysopen is not supported by fakefs'
+      end
     end
 
-
+    # Pathname class
     class Pathname    # * File *
-
       # See <tt>File.atime</tt>.  Returns last access time.
-      def atime() File.atime(@path) end
+      def atime
+        File.atime(@path)
+      end
 
-      # See <tt>File.ctime</tt>.  Returns last (directory entry, not file) change time.
-      def ctime() File.ctime(@path) end
+      # See <tt>File.ctime</tt>.
+      # Returns last (directory entry, not file) change time.
+      def ctime
+        File.ctime(@path)
+      end
 
       # See <tt>File.mtime</tt>.  Returns last modification time.
-      def mtime() File.mtime(@path) end
+      def mtime
+        File.mtime(@path)
+      end
 
       # See <tt>File.chmod</tt>.  Changes permissions.
-      def chmod(mode) File.chmod(mode, @path) end
+      def chmod(mode)
+        File.chmod(mode, @path)
+      end
 
       # See <tt>File.lchmod</tt>.
-      def lchmod(mode) File.lchmod(mode, @path) end
+      def lchmod(mode)
+        File.lchmod(mode, @path)
+      end
 
       # See <tt>File.chown</tt>.  Change owner and group of file.
-      def chown(owner, group) File.chown(owner, group, @path) end
+      def chown(owner, group)
+        File.chown(owner, group, @path)
+      end
 
       # See <tt>File.lchown</tt>.
-      def lchown(owner, group) File.lchown(owner, group, @path) end
+      def lchown(owner, group)
+        File.lchown(owner, group, @path)
+      end
 
-      # See <tt>File.fnmatch</tt>.  Return +true+ if the receiver matches the given
-      # pattern.
-      def fnmatch(pattern, *args) File.fnmatch(pattern, @path, *args) end
+      # See <tt>File.fnmatch</tt>.  Return +true+
+      # if the receiver matches the given pattern
+      def fnmatch(pattern, *args)
+        File.fnmatch(pattern, @path, *args)
+      end
 
       # See <tt>File.fnmatch?</tt> (same as #fnmatch).
-      def fnmatch?(pattern, *args) File.fnmatch?(pattern, @path, *args) end
+      def fnmatch?(pattern, *args)
+        File.fnmatch?(pattern, @path, *args)
+      end
 
       # See <tt>File.ftype</tt>.  Returns "type" of file ("file", "directory",
       # etc).
-      def ftype() File.ftype(@path) end
+      def ftype
+        File.ftype(@path)
+      end
 
       # See <tt>File.link</tt>.  Creates a hard link.
-      def make_link(old) File.link(old, @path) end
+      def make_link(old)
+        File.link(old, @path)
+      end
 
       # See <tt>File.open</tt>.  Opens the file for reading or writing.
       def open(*args, &block) # :yield: file
@@ -648,151 +727,233 @@ module FakeFS
       end
 
       # See <tt>File.readlink</tt>.  Read symbolic link.
-      def readlink() self.class.new(File.readlink(@path)) end
+      def readlink
+        self.class.new(File.readlink(@path))
+      end
 
       # See <tt>File.rename</tt>.  Rename the file.
-      def rename(to) File.rename(@path, to) end
+      def rename(to)
+        File.rename(@path, to)
+      end
 
       # See <tt>File.stat</tt>.  Returns a <tt>File::Stat</tt> object.
-      def stat() File.stat(@path) end
+      def stat
+        File.stat(@path)
+      end
 
       # See <tt>File.lstat</tt>.
-      def lstat() File.lstat(@path) end
+      def lstat
+        File.lstat(@path)
+      end
 
       # See <tt>File.symlink</tt>.  Creates a symbolic link.
-      def make_symlink(old) File.symlink(old, @path) end
+      def make_symlink(old)
+        File.symlink(old, @path)
+      end
 
       # See <tt>File.truncate</tt>.  Truncate the file to +length+ bytes.
-      def truncate(length) File.truncate(@path, length) end
+      def truncate(length)
+        File.truncate(@path, length)
+      end
 
       # See <tt>File.utime</tt>.  Update the access and modification times.
-      def utime(atime, mtime) File.utime(atime, mtime, @path) end
+      def utime(atime, mtime)
+        File.utime(atime, mtime, @path)
+      end
 
       # See <tt>File.basename</tt>.  Returns the last component of the path.
-      def basename(*args) self.class.new(File.basename(@path, *args)) end
+      def basename(*args)
+        self.class.new(File.basename(@path, *args))
+      end
 
-      # See <tt>File.dirname</tt>.  Returns all but the last component of the path.
-      def dirname() self.class.new(File.dirname(@path)) end
+      # See <tt>File.dirname</tt>.  Returns all but the last
+      # component of the path.
+      def dirname
+        self.class.new(File.dirname(@path))
+      end
 
       # See <tt>File.extname</tt>.  Returns the file's extension.
-      def extname() File.extname(@path) end
+      def extname
+        File.extname(@path)
+      end
 
       # See <tt>File.expand_path</tt>.
-      def expand_path(*args) self.class.new(File.expand_path(@path, *args)) end
+      def expand_path(*args)
+        self.class.new(File.expand_path(@path, *args))
+      end
 
       # See <tt>File.split</tt>.  Returns the #dirname and the #basename in an
       # Array.
-      def split() File.split(@path).map {|f| self.class.new(f) } end
+      def split
+        File.split(@path).map { |f| self.class.new(f) }
+      end
     end
 
-
+    # Pathname class
     class Pathname    # * FileTest *
-
       # See <tt>FileTest.blockdev?</tt>.
-      def blockdev?() FileTest.blockdev?(@path) end
+      def blockdev?
+        FileTest.blockdev?(@path)
+      end
 
       # See <tt>FileTest.chardev?</tt>.
-      def chardev?() FileTest.chardev?(@path) end
+      def chardev?
+        FileTest.chardev?(@path)
+      end
 
       # See <tt>FileTest.executable?</tt>.
-      def executable?() FileTest.executable?(@path) end
+      def executable?
+        FileTest.executable?(@path)
+      end
 
       # See <tt>FileTest.executable_real?</tt>.
-      def executable_real?() FileTest.executable_real?(@path) end
+      def executable_real?
+        FileTest.executable_real?(@path)
+      end
 
       # See <tt>FileTest.exist?</tt>.
-      def exist?() FileTest.exist?(@path) end
+      def exist?
+        FileTest.exist?(@path)
+      end
 
       # See <tt>FileTest.grpowned?</tt>.
-      def grpowned?() FileTest.grpowned?(@path) end
+      def grpowned?
+        FileTest.grpowned?(@path)
+      end
 
       # See <tt>FileTest.directory?</tt>.
-      def directory?() FileTest.directory?(@path) end
+      def directory?
+        FileTest.directory?(@path)
+      end
 
       # See <tt>FileTest.file?</tt>.
-      def file?() FileTest.file?(@path) end
+      def file?
+        FileTest.file?(@path)
+      end
 
       # See <tt>FileTest.pipe?</tt>.
-      def pipe?() FileTest.pipe?(@path) end
+      def pipe?
+        FileTest.pipe?(@path)
+      end
 
       # See <tt>FileTest.socket?</tt>.
-      def socket?() FileTest.socket?(@path) end
+      def socket?
+        FileTest.socket?(@path)
+      end
 
       # See <tt>FileTest.owned?</tt>.
-      def owned?() FileTest.owned?(@path) end
+      def owned?
+        FileTest.owned?(@path)
+      end
 
       # See <tt>FileTest.readable?</tt>.
-      def readable?() FileTest.readable?(@path) end
+      def readable?
+        FileTest.readable?(@path)
+      end
 
       # See <tt>FileTest.world_readable?</tt>.
-      def world_readable?() FileTest.world_readable?(@path) end
+      def world_readable?
+        FileTest.world_readable?(@path)
+      end
 
       # See <tt>FileTest.readable_real?</tt>.
-      def readable_real?() FileTest.readable_real?(@path) end
+      def readable_real?
+        FileTest.readable_real?(@path)
+      end
 
       # See <tt>FileTest.setuid?</tt>.
-      def setuid?() FileTest.setuid?(@path) end
+      def setuid?
+        FileTest.setuid?(@path)
+      end
 
       # See <tt>FileTest.setgid?</tt>.
-      def setgid?() FileTest.setgid?(@path) end
+      def setgid?
+        FileTest.setgid?(@path)
+      end
 
       # See <tt>FileTest.size</tt>.
-      def size() FileTest.size(@path) end
+      def size
+        FileTest.size(@path)
+      end
 
       # See <tt>FileTest.size?</tt>.
-      def size?() FileTest.size?(@path) end
+      def size?
+        FileTest.size?(@path)
+      end
 
       # See <tt>FileTest.sticky?</tt>.
-      def sticky?() FileTest.sticky?(@path) end
+      def sticky?
+        FileTest.sticky?(@path)
+      end
 
       # See <tt>FileTest.symlink?</tt>.
-      def symlink?() FileTest.symlink?(@path) end
+      def symlink?
+        FileTest.symlink?(@path)
+      end
 
       # See <tt>FileTest.writable?</tt>.
-      def writable?() FileTest.writable?(@path) end
+      def writable?
+        FileTest.writable?(@path)
+      end
 
       # See <tt>FileTest.world_writable?</tt>.
-      def world_writable?() FileTest.world_writable?(@path) end
+      def world_writable?
+        FileTest.world_writable?(@path)
+      end
 
       # See <tt>FileTest.writable_real?</tt>.
-      def writable_real?() FileTest.writable_real?(@path) end
+      def writable_real?
+        FileTest.writable_real?(@path)
+      end
 
       # See <tt>FileTest.zero?</tt>.
-      def zero?() FileTest.zero?(@path) end
+      def zero?
+        FileTest.zero?(@path)
+      end
     end
 
-
+    # Pathname class
     class Pathname    # * Dir *
       # See <tt>Dir.glob</tt>.  Returns or yields Pathname objects.
-      def Pathname.glob(*args) # :yield: pathname
+      def self.glob(*args) # :yield: pathname
         if block_given?
-          Dir.glob(*args) {|f| yield self.new(f) }
+          Dir.glob(*args) { |f| yield new(f) }
         else
-          Dir.glob(*args).map {|f| self.new(f) }
+          Dir.glob(*args).map { |f| new(f) }
         end
       end
 
-      # See <tt>Dir.getwd</tt>.  Returns the current working directory as a Pathname.
-      def Pathname.getwd() self.new(Dir.getwd) end
-      class << self; alias pwd getwd end
+      # See <tt>Dir.getwd</tt>.  Returns the current working directory
+      # as a Pathname.
+      def self.getwd
+        new(Dir.getwd)
+      end
+
+      class << self; alias_method :pwd, :getwd end
 
-      # Return the entries (files and subdirectories) in the directory, each as a
-      # Pathname object.
-      def entries() Dir.entries(@path).map {|f| self.class.new(f) } end
+      # Return the entries (files and subdirectories) in the directory, each as
+      # a Pathname object.
+      def entries
+        Dir.entries(@path).map { |f| self.class.new(f) }
+      end
 
-      # Iterates over the entries (files and subdirectories) in the directory.  It
-      # yields a Pathname object for each entry.
+      # Iterates over the entries (files and subdirectories) in the directory.
+      # It yields a Pathname object for each entry.
       #
       # This method has existed since 1.8.1.
-      def each_entry(&block) # :yield: pathname
-        Dir.foreach(@path) {|f| yield self.class.new(f) }
+      def each_entry(*) # :yield: pathname
+        Dir.foreach(@path) { |f| yield self.class.new(f) }
       end
 
       # See <tt>Dir.mkdir</tt>.  Create the referenced directory.
-      def mkdir(*args) Dir.mkdir(@path, *args) end
+      def mkdir(*args)
+        Dir.mkdir(@path, *args)
+      end
 
       # See <tt>Dir.rmdir</tt>.  Remove the referenced directory.
-      def rmdir() Dir.rmdir(@path) end
+      def rmdir
+        Dir.rmdir(@path)
+      end
 
       # See <tt>Dir.open</tt>.
       def opendir(&block) # :yield: dir
@@ -800,29 +961,30 @@ module FakeFS
       end
     end
 
-
+    # Pathname class
     class Pathname    # * Find *
       #
-      # Pathname#find is an iterator to traverse a directory tree in a depth first
-      # manner.  It yields a Pathname for each file under "this" directory.
+      # Pathname#find is an iterator to traverse a directory tree
+      # in a depth first manner.
+      # It yields a Pathname for each file under "this" directory.
       #
-      # Since it is implemented by <tt>find.rb</tt>, <tt>Find.prune</tt> can be used
-      # to control the traverse.
+      # Since it is implemented by <tt>find.rb</tt>, <tt>Find.prune</tt>
+      # can be used to control the traverse.
       #
-      # If +self+ is <tt>.</tt>, yielded pathnames begin with a filename in the
-      # current directory, not <tt>./</tt>.
+      # If +self+ is <tt>.</tt>, yielded pathnames begin with
+      # a filename in the current directory, not <tt>./</tt>.
       #
-      def find(&block) # :yield: pathname
+      def find(*) # :yield: pathname
         require 'find'
         if @path == '.'
-          Find.find(@path) {|f| yield self.class.new(f.sub(%r{\A\./}, '')) }
+          Find.find(@path) { |f| yield self.class.new(f.sub(%r{/\A\./}, '')) }
         else
-          Find.find(@path) {|f| yield self.class.new(f) }
+          Find.find(@path) { |f| yield self.class.new(f) }
         end
       end
     end
 
-
+    # Pathname class
     class Pathname    # * FileUtils *
       # See <tt>FileUtils.mkpath</tt>.  Creates a full path, including any
       # intermediate directories that don't yet exist.
@@ -842,23 +1004,21 @@ module FakeFS
       end
     end
 
-
+    # Pathname class
     class Pathname    # * mixed *
       # Removes a file or directory, using <tt>File.unlink</tt> or
       # <tt>Dir.unlink</tt> as necessary.
-      def unlink()
-        begin
-          Dir.unlink @path
-        rescue Errno::ENOTDIR
-          File.unlink @path
-        end
+      def unlink
+        Dir.unlink @path if File.directory? @path
+        File.unlink @path unless File.directory? @path
       end
-      alias delete unlink
+
+      alias_method :delete, :unlink
     end
 
+    # Pathname class
     class Pathname
       undef =~
     end
   end # RUBY_VERSION >= 1.9.3
 end
-
diff --git a/lib/fakefs/safe.rb b/lib/fakefs/safe.rb
index 783de74..04e955e 100644
--- a/lib/fakefs/safe.rb
+++ b/lib/fakefs/safe.rb
@@ -9,5 +9,5 @@ require 'fakefs/fileutils'
 require 'fakefs/file'
 require 'fakefs/file_test'
 require 'fakefs/dir'
-require 'fakefs/pathname' if RUBY_VERSION >= "1.9.3"
-
+require 'fakefs/pathname' if RUBY_VERSION >= '1.9.3'
+require 'fakefs/kernel'
diff --git a/lib/fakefs/spec_helpers.rb b/lib/fakefs/spec_helpers.rb
index 0123057..dfa3e4c 100644
--- a/lib/fakefs/spec_helpers.rb
+++ b/lib/fakefs/spec_helpers.rb
@@ -1,6 +1,8 @@
-# FakeFS::SpecHelpers provides a simple macro for RSpec example groups to turn FakeFS on and off.
-# To use it simply require 'fakefs/spec_helpers', then include FakeFS::SpecHelpers into any
-# example groups that you wish to use FakeFS in. For example:
+# FakeFS::SpecHelpers provides a simple macro for RSpec example
+# groups to turn FakeFS on and off.
+# To use it simply require 'fakefs/spec_helpers', then include
+# FakeFS::SpecHelpers into any example groups that you wish
+# to use FakeFS in. For example:
 #
 #   require 'fakefs/spec_helpers'
 #
@@ -9,37 +11,61 @@
 #     ...
 #   end
 #
-# Alternatively, you can include FakeFS::SpecHelpers in all your example groups using RSpec's
-# configuration block in your spec helper:
+# By default, including FakeFS::SpecHelpers will run for each
+# example inside a describe block.
+# If you want to turn on FakeFS one time only for all your examples,
+# you will need to include FakeFS::SpecHelpers::All.
+#
+# Alternatively, you can include FakeFS::SpecHelpers in all your
+# example groups using RSpec's configuration block in
+# your spec helper:
 #
 #   require 'fakefs/spec_helpers'
 #
-#   Spec::Runner.configure do |config|
+#   RSpec.configure do |config|
 #     config.include FakeFS::SpecHelpers
 #   end
 #
-# If you do the above then use_fakefs will be available in all of your example groups.
+# If you do the above then use_fakefs will be available in all of
+# your example groups.
 #
 require 'fakefs/safe'
 
+# FakeFS module
 module FakeFS
+  def use_fakefs(describe_block, opts)
+    describe_block.before opts[:with] do
+      FakeFS.activate!
+    end
+
+    describe_block.after opts[:with] do
+      FakeFS.deactivate!
+      FakeFS::FileSystem.clear if opts[:with] == :each
+    end
+  end
+
+  # Module SpecHelpers
   module SpecHelpers
+    include ::FakeFS
+
     def self.extended(example_group)
-      example_group.use_fakefs(example_group)
+      example_group.use_fakefs(example_group, with: :each)
     end
 
     def self.included(example_group)
       example_group.extend self
     end
 
-    def use_fakefs(describe_block)
-      describe_block.before :each do
-        FakeFS.activate!
+    # Module All
+    module All
+      include ::FakeFS
+
+      def self.extended(example_group)
+        example_group.use_fakefs(example_group, with: :all)
       end
 
-      describe_block.after :each do
-        FakeFS.deactivate!
-        FakeFS::FileSystem.clear
+      def self.included(example_group)
+        example_group.extend self
       end
     end
   end
diff --git a/lib/fakefs/version.rb b/lib/fakefs/version.rb
index b8e73bd..0a820f1 100644
--- a/lib/fakefs/version.rb
+++ b/lib/fakefs/version.rb
@@ -1,6 +1,7 @@
 module FakeFS
+  # Version module
   module Version
-    VERSION = "0.4.2"
+    VERSION = '0.6.7'
 
     def self.to_s
       VERSION
diff --git a/metadata.yml b/metadata.yml
index d6ae6d7..6ab37db 100644
--- a/metadata.yml
+++ b/metadata.yml
@@ -1,84 +1,121 @@
 --- !ruby/object:Gem::Specification
 name: fakefs
 version: !ruby/object:Gem::Version
-  version: 0.4.2
-  prerelease: 
+  version: 0.6.7
 platform: ruby
 authors:
 - Chris Wanstrath
 - Scott Taylor
 - Jeff Hodges
 - Pat Nakajima
+- Brian Donovan
 autorequire: 
 bindir: bin
 cert_chain: []
-date: 2012-11-24 00:00:00.000000000 Z
+date: 2015-02-15 00:00:00.000000000 Z
 dependencies:
 - !ruby/object:Gem::Dependency
+  name: bundler
+  requirement: !ruby/object:Gem::Requirement
+    requirements:
+    - - "~>"
+      - !ruby/object:Gem::Version
+        version: '1.3'
+  type: :development
+  prerelease: false
+  version_requirements: !ruby/object:Gem::Requirement
+    requirements:
+    - - "~>"
+      - !ruby/object:Gem::Version
+        version: '1.3'
+- !ruby/object:Gem::Dependency
+  name: rake
+  requirement: !ruby/object:Gem::Requirement
+    requirements:
+    - - "~>"
+      - !ruby/object:Gem::Version
+        version: '10.3'
+  type: :development
+  prerelease: false
+  version_requirements: !ruby/object:Gem::Requirement
+    requirements:
+    - - "~>"
+      - !ruby/object:Gem::Version
+        version: '10.3'
+- !ruby/object:Gem::Dependency
   name: rspec
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - "~>"
+      - !ruby/object:Gem::Version
+        version: '3.1'
+  type: :development
+  prerelease: false
+  version_requirements: !ruby/object:Gem::Requirement
+    requirements:
+    - - "~>"
+      - !ruby/object:Gem::Version
+        version: '3.1'
+- !ruby/object:Gem::Dependency
+  name: rubocop
+  requirement: !ruby/object:Gem::Requirement
+    requirements:
+    - - "~>"
       - !ruby/object:Gem::Version
-        version: '0'
+        version: '0.25'
   type: :development
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - "~>"
       - !ruby/object:Gem::Version
-        version: '0'
+        version: '0.25'
 - !ruby/object:Gem::Dependency
-  name: jeweler
+  name: minitest
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - "~>"
       - !ruby/object:Gem::Version
-        version: '0'
+        version: '5.5'
   type: :development
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - "~>"
       - !ruby/object:Gem::Version
-        version: '0'
+        version: '5.5'
 - !ruby/object:Gem::Dependency
-  name: rdiscount
+  name: minitest-rg
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - "~>"
       - !ruby/object:Gem::Version
-        version: '0'
+        version: '5.1'
   type: :development
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - "~>"
       - !ruby/object:Gem::Version
-        version: '0'
+        version: '5.1'
 description: A fake filesystem. Use it in your tests.
-email: chris at ozmm.org
+email:
+- chris at ozmm.org
 executables: []
 extensions: []
-extra_rdoc_files:
-- LICENSE
-- README.markdown
+extra_rdoc_files: []
 files:
-- .autotest
-- .rspec
-- .travis.yml
+- ".autotest"
+- ".gitignore"
+- ".rspec"
+- ".rubocop.yml"
+- ".travis.yml"
 - CONTRIBUTORS
 - Gemfile
-- Gemfile.lock
 - LICENSE
 - README.markdown
 - Rakefile
+- etc/git-rank-contributors
 - fakefs.gemspec
 - lib/fakefs.rb
 - lib/fakefs/base.rb
@@ -90,13 +127,16 @@ files:
 - lib/fakefs/file_system.rb
 - lib/fakefs/file_test.rb
 - lib/fakefs/fileutils.rb
+- lib/fakefs/kernel.rb
 - lib/fakefs/pathname.rb
 - lib/fakefs/safe.rb
 - lib/fakefs/spec_helpers.rb
 - lib/fakefs/version.rb
+- spec/fakefs/fakefs_bug_ruby_2.1.0-preview2_spec.rb
 - spec/fakefs/spec_helpers_spec.rb
 - spec/spec.opts
 - spec/spec_helper.rb
+- test/dir/tempfile_test.rb
 - test/fake/file/join_test.rb
 - test/fake/file/lstat_test.rb
 - test/fake/file/stat_test.rb
@@ -106,34 +146,52 @@ files:
 - test/fake/symlink_test.rb
 - test/fakefs_test.rb
 - test/file/stat_test.rb
+- test/kernel_test.rb
+- test/pathname_test.rb
 - test/safe_test.rb
 - test/test_helper.rb
 - test/verify.rb
 homepage: http://github.com/defunkt/fakefs
-licenses: []
+licenses:
+- MIT
+metadata: {}
 post_install_message: 
 rdoc_options: []
 require_paths:
 - lib
 required_ruby_version: !ruby/object:Gem::Requirement
-  none: false
   requirements:
-  - - ! '>='
+  - - ">="
     - !ruby/object:Gem::Version
       version: '0'
-      segments:
-      - 0
-      hash: 4092255673165272959
 required_rubygems_version: !ruby/object:Gem::Requirement
-  none: false
   requirements:
-  - - ! '>='
+  - - ">="
     - !ruby/object:Gem::Version
       version: '0'
 requirements: []
 rubyforge_project: 
-rubygems_version: 1.8.24
+rubygems_version: 2.4.5
 signing_key: 
-specification_version: 3
+specification_version: 4
 summary: A fake filesystem. Use it in your tests.
-test_files: []
+test_files:
+- spec/fakefs/fakefs_bug_ruby_2.1.0-preview2_spec.rb
+- spec/fakefs/spec_helpers_spec.rb
+- spec/spec.opts
+- spec/spec_helper.rb
+- test/dir/tempfile_test.rb
+- test/fake/file/join_test.rb
+- test/fake/file/lstat_test.rb
+- test/fake/file/stat_test.rb
+- test/fake/file/sysseek_test.rb
+- test/fake/file/syswrite_test.rb
+- test/fake/file_test.rb
+- test/fake/symlink_test.rb
+- test/fakefs_test.rb
+- test/file/stat_test.rb
+- test/kernel_test.rb
+- test/pathname_test.rb
+- test/safe_test.rb
+- test/test_helper.rb
+- test/verify.rb
diff --git a/spec/fakefs/fakefs_bug_ruby_2.1.0-preview2_spec.rb b/spec/fakefs/fakefs_bug_ruby_2.1.0-preview2_spec.rb
new file mode 100644
index 0000000..6a64311
--- /dev/null
+++ b/spec/fakefs/fakefs_bug_ruby_2.1.0-preview2_spec.rb
@@ -0,0 +1,18 @@
+require 'find'
+require 'fakefs/spec_helpers'
+
+RSpec.configure do |c|
+  c.mock_with(:rspec)
+  c.include(FakeFS::SpecHelpers, fakefs: true)
+  c.disable_monkey_patching!
+end
+
+if RUBY_VERSION >= '2.1'
+  RSpec.describe 'Find.find', fakefs: true do
+    it 'does not give an ArgumentError' do
+      FileUtils.mkdir_p('/tmp/foo')
+      found = Find.find('/tmp').to_a
+      expect(found).to eq(%w(/tmp /tmp/foo))
+    end
+  end
+end
diff --git a/spec/fakefs/spec_helpers_spec.rb b/spec/fakefs/spec_helpers_spec.rb
index 8a6f801..04996d7 100644
--- a/spec/fakefs/spec_helpers_spec.rb
+++ b/spec/fakefs/spec_helpers_spec.rb
@@ -1,57 +1,102 @@
 require 'spec_helper'
 
+# FakeFs module for tests
 module FakeFS
-  describe SpecHelpers do
+  RSpec.describe SpecHelpers do
     before do
       @rspec_example_group = Class.new do
-        def self.before(sym = :each)
+        def self.before(_sym = :each)
           yield if block_given?
         end
 
-        def self.after(sym = :each)
+        def self.after(_sym = :each)
           yield if block_given?
         end
       end
     end
 
-    describe "when extending" do
-      context "before each" do
-        it "should call it" do
-          @rspec_example_group.should_receive(:before).with(:each)
+    describe 'when extending' do
+      context 'before each' do
+        it 'should call it' do
+          expect(@rspec_example_group).to receive(:before).with(:each)
           @rspec_example_group.extend FakeFS::SpecHelpers
         end
 
-        it "should call FakeFS.activate!" do
-          FakeFS.should_receive(:activate!)
+        it 'should call FakeFS.activate!' do
+          expect(FakeFS).to receive(:activate!)
           @rspec_example_group.extend FakeFS::SpecHelpers
         end
       end
 
-      context "after each" do
-        it "should call it" do
-          @rspec_example_group.should_receive(:after).with(:each)
+      context 'after each' do
+        it 'should call it' do
+          expect(@rspec_example_group).to receive(:after).with(:each)
           @rspec_example_group.extend FakeFS::SpecHelpers
         end
 
-        it "should deactivate fakefs" do
-          FakeFS.should_receive(:deactivate!)
+        it 'should deactivate fakefs' do
+          expect(FakeFS).to receive(:deactivate!)
           @rspec_example_group.extend FakeFS::SpecHelpers
         end
 
-        it "should clear the fakefs filesystem for the next run" do
-          FakeFS::FileSystem.should_receive(:clear)
+        it 'should clear the fakefs filesystem for the next run' do
+          expect(FakeFS::FileSystem).to receive(:clear)
           @rspec_example_group.extend FakeFS::SpecHelpers
         end
       end
     end
 
-    describe "when including" do
-      it "should call before :each" do
-        @rspec_example_group.should_receive(:before)
+    describe 'when including' do
+      it 'should call before :each' do
+        expect(@rspec_example_group).to receive(:before)
         @rspec_example_group.class_eval do
           include FakeFS::SpecHelpers
         end
       end
     end
+
+    describe SpecHelpers::All do
+      describe 'when extending' do
+        context 'before :all' do
+          it 'should call it' do
+            expect(@rspec_example_group).to receive(:before).with(:all)
+            @rspec_example_group.extend FakeFS::SpecHelpers::All
+          end
+
+          it 'should call FakeFS.activate!' do
+            expect(FakeFS).to receive(:activate!)
+            @rspec_example_group.extend FakeFS::SpecHelpers::All
+          end
+        end
+
+        context 'after :all' do
+          it 'should call it' do
+            expect(@rspec_example_group).to receive(:after).with(:all)
+            @rspec_example_group.extend FakeFS::SpecHelpers::All
+          end
+
+          it 'should call FakeFS.deactivate!' do
+            expect(FakeFS).to receive(:deactivate!)
+            @rspec_example_group.extend FakeFS::SpecHelpers::All
+          end
+
+          it 'should not call FakeFS::FileSystem.clear' do
+            expect(FakeFS::FileSystem).to_not receive(:clear)
+            @rspec_example_group.extend FakeFS::SpecHelpers::All
+          end
+        end
+      end
+
+      describe 'when including' do
+        context 'before :all' do
+          it 'should call it' do
+            expect(@rspec_example_group).to receive(:before)
+            @rspec_example_group.class_eval do
+              include FakeFS::SpecHelpers::All
+            end
+          end
+        end
+      end
+    end
   end
 end
diff --git a/test/dir/tempfile_test.rb b/test/dir/tempfile_test.rb
new file mode 100644
index 0000000..5a55dff
--- /dev/null
+++ b/test/dir/tempfile_test.rb
@@ -0,0 +1,21 @@
+require 'test_helper'
+require 'tempfile'
+
+# Tempfile test class
+class TempfileTest < Minitest::Test
+  include FakeFS
+
+  if RUBY_VERSION >= '2.1'
+    def test_should_not_raise_error
+      FakeFS do
+        # nothing raised
+        FileUtils.mkdir_p('/tmp')
+        Tempfile.open('test')
+      end
+    end
+  else
+    def test_noop
+      # TODO: Remove me when we add non-2.1 tests.
+    end
+  end
+end
diff --git a/test/fake/file/join_test.rb b/test/fake/file/join_test.rb
index 966273a..d7dd021 100644
--- a/test/fake/file/join_test.rb
+++ b/test/fake/file/join_test.rb
@@ -1,6 +1,7 @@
-require "test_helper"
+require 'test_helper'
 
-class FileJoin < Test::Unit::TestCase
+# File join test class
+class FileJoin < Minitest::Test
   def setup
     FakeFS.activate!
   end
@@ -10,10 +11,10 @@ class FileJoin < Test::Unit::TestCase
   end
 
   [
-    ["a", "b"],  ["a/", "b"], ["a", "/b"], ["a/", "/b"], ["a", "/", "b"]
+    %w(a b),  %w(a/ b), %w(a /b), %w(a/ /b), %w(a / b)
   ].each_with_index do |args, i|
     define_method "test_file_join_#{i}" do
       assert_equal RealFile.join(args), File.join(args)
     end
   end
-end
\ No newline at end of file
+end
diff --git a/test/fake/file/lstat_test.rb b/test/fake/file/lstat_test.rb
index 4b01838..128ca1b 100644
--- a/test/fake/file/lstat_test.rb
+++ b/test/fake/file/lstat_test.rb
@@ -1,6 +1,7 @@
-require "test_helper"
+require 'test_helper'
 
-class FileStat < Test::Unit::TestCase
+# File stat test class
+class FileStat < Minitest::Test
   def setup
     FakeFS.activate!
     FakeFS::FileSystem.clear
@@ -11,49 +12,49 @@ class FileStat < Test::Unit::TestCase
   end
 
   def test_calling_lstat_should_create_a_new_file_stat_object
-    File.open("foo", "w") do |f|
-      f << "bar"
+    File.open('foo', 'w') do |f|
+      f << 'bar'
     end
 
-    File.open("foo") do |f|
+    File.open('foo') do |f|
       assert_equal File::Stat, f.lstat.class
     end
   end
 
   def test_lstat_should_use_correct_file
-    File.open("bar", "w") do |f|
-      f << "1"
+    File.open('bar', 'w') do |f|
+      f << '1'
     end
 
-    File.open("bar") do |f|
+    File.open('bar') do |f|
       assert_equal 1, f.lstat.size
     end
   end
 
   def test_lstat_should_report_on_symlink_itself
-    File.open("foo", "w") { |f| f << "some content" }
-    File.symlink "foo", "my_symlink"
+    File.open('foo', 'w') { |f| f << 'some content' }
+    File.symlink 'foo', 'my_symlink'
 
-    assert_not_equal File.lstat("my_symlink").size, File.lstat("foo").size
+    refute_equal File.lstat('my_symlink').size, File.lstat('foo').size
   end
 
   def test_should_report_on_symlink_itself_with_size_instance_method
-    File.open("foo", "w") { |f| f << "some content" }
-    File.symlink "foo", "my_symlink"
+    File.open('foo', 'w') { |f| f << 'some content' }
+    File.symlink 'foo', 'my_symlink'
 
-    file = File.open("foo")
-    symlink = File.open("my_symlink")
+    file = File.open('foo')
+    symlink = File.open('my_symlink')
 
-    assert_not_equal file.lstat.size, symlink.lstat.size
+    refute_equal file.lstat.size, symlink.lstat.size
   end
 
   def test_symlink_size_is_size_of_path_pointed_to
-    File.open("a", "w") { |x| x << "foobarbazfoobarbaz" }
-    File.symlink "a", "one_char_symlink"
-    assert_equal 1, File.lstat("one_char_symlink").size
+    File.open('a', 'w') { |x| x << 'foobarbazfoobarbaz' }
+    File.symlink 'a', 'one_char_symlink'
+    assert_equal 1, File.lstat('one_char_symlink').size
 
-    File.open("ab", "w") { |x| x << "foobarbazfoobarbaz" }
-    File.symlink "ab", "two_char_symlink"
-    assert_equal 2, File.lstat("two_char_symlink").size
+    File.open('ab', 'w') { |x| x << 'foobarbazfoobarbaz' }
+    File.symlink 'ab', 'two_char_symlink'
+    assert_equal 2, File.lstat('two_char_symlink').size
   end
-end
\ No newline at end of file
+end
diff --git a/test/fake/file/stat_test.rb b/test/fake/file/stat_test.rb
index 6e6e54c..9a3e926 100644
--- a/test/fake/file/stat_test.rb
+++ b/test/fake/file/stat_test.rb
@@ -1,6 +1,7 @@
-require "test_helper"
+require 'test_helper'
 
-class FileStat < Test::Unit::TestCase
+# File stat test class
+class FileStat < Minitest::Test
   def setup
     FakeFS.activate!
     FakeFS::FileSystem.clear
@@ -11,29 +12,29 @@ class FileStat < Test::Unit::TestCase
   end
 
   def test_calling_stat_should_create_a_new_file_stat_object
-    File.open("foo", "w") do |f|
-      f << "bar"
+    File.open('foo', 'w') do |f|
+      f << 'bar'
     end
 
-    File.open("foo") do |f|
+    File.open('foo') do |f|
       assert_equal File::Stat, f.stat.class
     end
   end
 
   def test_stat_should_use_correct_file
-    File.open("bar", "w") do |f|
-      f << "1"
+    File.open('bar', 'w') do |f|
+      f << '1'
     end
 
-    File.open("bar") do |f|
+    File.open('bar') do |f|
       assert_equal 1, f.stat.size
     end
   end
 
   def test_stat_should_report_on_symlink_pointer
-    File.open("foo", "w") { |f| f << "some content" }
-    File.symlink "foo", "my_symlink"
+    File.open('foo', 'w') { |f| f << 'some content' }
+    File.symlink 'foo', 'my_symlink'
 
-    assert_equal File.stat("my_symlink").size, File.stat("foo").size
+    assert_equal File.stat('my_symlink').size, File.stat('foo').size
   end
-end
\ No newline at end of file
+end
diff --git a/test/fake/file/sysseek_test.rb b/test/fake/file/sysseek_test.rb
index 531b21a..0945433 100644
--- a/test/fake/file/sysseek_test.rb
+++ b/test/fake/file/sysseek_test.rb
@@ -1,6 +1,7 @@
-require "test_helper"
+require 'test_helper'
 
-class FileSysSeek < Test::Unit::TestCase
+# File SysSeek test class
+class FileSysSeek < Minitest::Test
   def setup
     FakeFS.activate!
     FakeFS::FileSystem.clear
@@ -11,11 +12,11 @@ class FileSysSeek < Test::Unit::TestCase
   end
 
   def test_should_seek_to_position
-    file = File.open("foo", "w") do |f|
-      f << "0123456789"
+    File.open('foo', 'w') do |f|
+      f << '0123456789'
     end
 
-    File.open("foo", "r") do |f|
+    File.open('foo', 'r') do |f|
       f.sysseek(3)
       assert_equal 3, f.pos
 
@@ -25,20 +26,20 @@ class FileSysSeek < Test::Unit::TestCase
   end
 
   def test_seek_returns_offset_into_file
-    File.open("foo", "w") do |f|
+    File.open('foo', 'w') do |f|
       # 66 chars long
-      str = "0123456789" +
-            "0123456789" +
-            "0123456789" +
-            "0123456789" +
-            "0123456789" +
-            "0123456789" +
-            "012345"
+      str = '0123456789' \
+            '0123456789' \
+            '0123456789' \
+            '0123456789' \
+            '0123456789' \
+            '0123456789' \
+            '012345'
 
       f << str
     end
 
-    f = File.open("foo")
+    f = File.open('foo')
     assert_equal 53, f.sysseek(-13, IO::SEEK_END)
   end
-end
\ No newline at end of file
+end
diff --git a/test/fake/file/syswrite_test.rb b/test/fake/file/syswrite_test.rb
index 499ac2f..270ff1e 100644
--- a/test/fake/file/syswrite_test.rb
+++ b/test/fake/file/syswrite_test.rb
@@ -1,6 +1,7 @@
-require "test_helper"
+require 'test_helper'
 
-class FileSysWriteTest < Test::Unit::TestCase
+# File SysWrite test class
+class FileSysWriteTest < Minitest::Test
   def setup
     FakeFS.activate!
     FakeFS::FileSystem.clear
@@ -11,52 +12,52 @@ class FileSysWriteTest < Test::Unit::TestCase
   end
 
   def test_returns_one_byte_when_written
-    f = File.open "foo", "w"
-    result = f.syswrite "a"
+    f = File.open 'foo', 'w'
+    result = f.syswrite 'a'
     assert_equal 1, result
   end
 
   def test_returns_two_bytes_when_two_written
-    f = File.open "foo", "w"
-    result = f.syswrite "ab"
+    f = File.open 'foo', 'w'
+    result = f.syswrite 'ab'
     assert_equal 2, result
   end
 
   def test_syswrite_writes_file
-    f = File.open "foo", "w"
-    f.syswrite "abcdef"
+    f = File.open 'foo', 'w'
+    f.syswrite 'abcdef'
     f.close
 
-    assert_equal "abcdef", File.read("foo")
+    assert_equal 'abcdef', File.read('foo')
   end
 
   def test_writes_to_the_actual_position_when_called_after_buffered_io_read
-    File.open("foo", "w") do |file|
-      file.syswrite("012345678901234567890123456789")
+    File.open('foo', 'w') do |file|
+      file.syswrite('012345678901234567890123456789')
     end
 
-    file = File.open("foo", "r+")
+    file = File.open('foo', 'r+')
     file.read(5)
-    file.syswrite("abcde")
+    file.syswrite('abcde')
 
-    File.open("foo") do |file|
-      assert_equal "01234abcde", file.sysread(10)
+    File.open('foo') do |f|
+      assert_equal '01234abcde', f.sysread(10)
     end
   end
 
   def test_writes_all_of_the_strings_bytes_but_does_not_buffer_them
-    File.open("foo", "w") do |file|
-      file.syswrite("012345678901234567890123456789")
+    File.open('foo', 'w') do |file|
+      file.syswrite('012345678901234567890123456789')
     end
 
-    file = File.open("foo", "r+")
-    written = file.syswrite("abcde")
+    file = File.open('foo', 'r+')
+    file.syswrite('abcde')
 
-    File.open("foo") do |file|
-      assert_equal "abcde56789", file.sysread(10)
-      file.seek(0)
-      file.fsync
-      assert_equal "abcde56789", file.sysread(10)
+    File.open('foo') do |f|
+      assert_equal 'abcde56789', f.sysread(10)
+      f.seek(0)
+      f.fsync
+      assert_equal 'abcde56789', f.sysread(10)
     end
   end
-end
\ No newline at end of file
+end
diff --git a/test/fake/file_test.rb b/test/fake/file_test.rb
index 9457aae..4d2d96f 100644
--- a/test/fake/file_test.rb
+++ b/test/fake/file_test.rb
@@ -1,6 +1,7 @@
-require "test_helper"
+require 'test_helper'
 
-class FakeFileTest < Test::Unit::TestCase
+# Fake File test class
+class FakeFileTest < Minitest::Test
   include FakeFS
 
   def setup
@@ -10,12 +11,12 @@ class FakeFileTest < Test::Unit::TestCase
   end
 
   def test_fake_file_has_empty_content_by_default
-    assert_equal "", @file.content
+    assert_equal '', @file.content
   end
 
   def test_fake_file_can_read_and_write_to_content
-    @file.content = "foobar"
-    assert_equal "foobar", @file.content
+    @file.content = 'foobar'
+    assert_equal 'foobar', @file.content
   end
 
   def test_fake_file_has_1_link_by_default
@@ -64,28 +65,28 @@ class FakeFileTest < Test::Unit::TestCase
 
     @file.link other_file
 
-    @file.content = "foobar"
+    @file.content = 'foobar'
 
-    assert_equal "foobar", other_file.content
+    assert_equal 'foobar', other_file.content
   end
 
   def test_clone_creates_new_inode
     clone = @file.clone
-    assert !clone.inode.equal?(@file.inode)
+    refute clone.inode.equal?(@file.inode)
   end
 
   def test_cloning_does_not_use_same_content_object
     clone = @file.clone
 
-    clone.content = "foo"
-    @file.content = "bar"
+    clone.content = 'foo'
+    @file.content = 'bar'
 
-    assert_equal "foo", clone.content
-    assert_equal "bar", @file.content
+    assert_equal 'foo', clone.content
+    assert_equal 'bar', @file.content
   end
 
   def test_raises_an_error_with_the_correct_path
-    path = "/some/non/existing/file"
+    path = '/some/non/existing/file'
     begin
       FakeFS::File.new path
       msg = nil
@@ -94,4 +95,18 @@ class FakeFileTest < Test::Unit::TestCase
     end
     assert_equal "No such file or directory - #{path}", msg
   end
+
+  def test_file_size_question_works
+    assert_nil FileTest.size?('does-not-exist.txt')
+
+    File.open('empty.txt', 'w') do |f|
+      f << ''
+    end
+    assert_nil FileTest.size?('empty.txt')
+
+    File.open('one-char.txt', 'w') do |f|
+      f << 'a'
+    end
+    assert_equal 1, FileTest.size?('one-char.txt')
+  end
 end
diff --git a/test/fake/symlink_test.rb b/test/fake/symlink_test.rb
index 8eae46d..a443057 100644
--- a/test/fake/symlink_test.rb
+++ b/test/fake/symlink_test.rb
@@ -1,10 +1,33 @@
-require "test_helper"
+require 'test_helper'
 
-class FakeSymlinkTest < Test::Unit::TestCase
+# Fake symlink test class
+class FakeSymlinkTest < Minitest::Test
   include FakeFS
 
   def test_symlink_has_method_missing_as_private
-    methods = FakeSymlink.private_instance_methods.map { |m| m.to_s }
-    assert methods.include?("method_missing")
+    methods = FakeSymlink.private_instance_methods.map(&:to_s)
+    assert methods.include?('method_missing')
+  end
+
+  def test_symlink_respond_to_accepts_multiple_params
+    fake_symlink = FakeSymlink.new('foo')
+    assert fake_symlink.respond_to?(:to_s, false),
+           'has public method \#to_s'
+    assert fake_symlink.respond_to?(:to_s, true),
+           'has public or private method \#to_s'
+    refute fake_symlink.respond_to?(:initialize, false),
+           'has private method \#initialize'
+    assert fake_symlink.respond_to?(:initialize, true),
+           'has private method \#initialize'
+  end
+
+  def test_symlink_respond_to_uses_same_param_defaults
+    fake_symlink = FakeSymlink.new('foo')
+    assert_equal fake_symlink.respond_to?(:to_s),
+                 fake_symlink.entry.respond_to?(:to_s)
+    refute_equal fake_symlink.respond_to?(:to_s),
+                 fake_symlink.entry.respond_to?(:initialize)
+    assert_equal fake_symlink.respond_to?(:initialize),
+                 fake_symlink.entry.respond_to?(:initialize)
   end
 end
diff --git a/test/fakefs_test.rb b/test/fakefs_test.rb
old mode 100644
new mode 100755
index 955bb31..eb64480
--- a/test/fakefs_test.rb
+++ b/test/fakefs_test.rb
@@ -1,115 +1,182 @@
-require "test_helper"
-
-class FakeFSTest < Test::Unit::TestCase
-  include FakeFS
+# -*- coding: utf-8 -*-
+require 'test_helper'
 
+# FakeFS tests
+class FakeFSTest < Minitest::Test
   def setup
+    act_on_real_fs do
+      File.umask(0006)
+      FileUtils.rm_rf(real_file_sandbox)
+      FileUtils.mkdir_p(real_file_sandbox)
+      FileUtils.chmod(0777, real_file_sandbox)
+    end
+
     FakeFS.activate!
-    FileSystem.clear
+    FakeFS::FileSystem.clear
   end
 
   def teardown
     FakeFS.deactivate!
+
+    act_on_real_fs do
+      FileUtils.rm_rf(real_file_sandbox)
+    end
   end
 
   def test_can_be_initialized_empty
-    fs = FileSystem
+    fs = FakeFS::FileSystem
     assert_equal 0, fs.files.size
   end
 
   def xtest_can_be_initialized_with_an_existing_directory
-    fs = FileSystem
+    fs = FakeFS::FileSystem
     fs.clone(File.expand_path(File.dirname(__FILE__))).inspect
     assert_equal 1, fs.files.size
   end
 
   def test_can_create_directories_with_file_utils_mkdir_p
-    FileUtils.mkdir_p("/path/to/dir")
-    assert_kind_of FakeDir, FileSystem.fs['path']['to']['dir']
+    FileUtils.mkdir_p('/path/to/dir')
+    assert_kind_of FakeFS::FakeDir, FakeFS::FileSystem.fs['path']['to']['dir']
+  end
+
+  def test_can_cd_to_directory_with_block
+    FileUtils.mkdir_p('/path/to/dir')
+    new_path = nil
+    FileUtils.cd('/path/to') do
+      new_path = Dir.getwd
+    end
+
+    assert_equal new_path, '/path/to'
+  end
+
+  def test_can_create_a_list_of_directories_with_file_utils_mkdir_p
+    FileUtils.mkdir_p(%w(/path/to/dir1 /path/to/dir2))
+    assert_kind_of FakeFS::FakeDir, FakeFS::FileSystem.fs['path']['to']['dir1']
+    assert_kind_of FakeFS::FakeDir, FakeFS::FileSystem.fs['path']['to']['dir2']
   end
 
   def test_can_create_directories_with_options
-    FileUtils.mkdir_p("/path/to/dir", :mode => 0755)
-    assert_kind_of FakeDir, FileSystem.fs['path']['to']['dir']
+    FileUtils.mkdir_p('/path/to/dir', mode: 0755)
+    assert_kind_of FakeFS::FakeDir, FakeFS::FileSystem.fs['path']['to']['dir']
   end
 
   def test_can_create_directories_with_file_utils_mkdir
-    FileUtils.mkdir_p("/path/to/dir")
-    FileUtils.mkdir("/path/to/dir/subdir")
-    assert_kind_of FakeDir, FileSystem.fs['path']['to']['dir']['subdir']
+    FileUtils.mkdir_p('/path/to/dir')
+    FileUtils.mkdir('/path/to/dir/subdir')
+    assert_kind_of FakeFS::FakeDir, FakeFS::FileSystem.fs['path']['to']['dir']['subdir']
+  end
+
+  def test_can_create_a_list_of_directories_with_file_utils_mkdir
+    FileUtils.mkdir_p('/path/to/dir')
+    FileUtils.mkdir(%w(/path/to/dir/subdir1 /path/to/dir/subdir2))
+    assert_kind_of FakeFS::FakeDir, FakeFS::FileSystem.fs['path']['to']['dir']['subdir1']
+    assert_kind_of FakeFS::FakeDir, FakeFS::FileSystem.fs['path']['to']['dir']['subdir2']
   end
 
   def test_raises_error_when_creating_a_new_dir_with_mkdir_in_non_existent_path
     assert_raises Errno::ENOENT do
-      FileUtils.mkdir("/this/path/does/not/exists/newdir")
+      FileUtils.mkdir('/this/path/does/not/exists/newdir')
+    end
+  end
+
+  def test_raises_error_when_creating_a_new_dir_over_existing_file
+    File.open('file', 'w') { |f| f << 'This is a file, not a directory.' }
+
+    assert_raises Errno::EEXIST do
+      FileUtils.mkdir_p('file/subdir')
+    end
+
+    FileUtils.mkdir('dir')
+    File.open('dir/subfile', 'w') { |f| f << 'This is a file inside a directory.' }
+
+    assert_raises Errno::EEXIST do
+      FileUtils.mkdir_p('dir/subfile/subdir')
     end
   end
 
   def test_can_create_directories_with_mkpath
-    FileUtils.mkpath("/path/to/dir")
-    assert_kind_of FakeDir, FileSystem.fs['path']['to']['dir']
+    FileUtils.mkpath('/path/to/dir')
+    assert_kind_of FakeFS::FakeDir, FakeFS::FileSystem.fs['path']['to']['dir']
   end
 
   def test_can_create_directories_with_mkpath_and_options
-    FileUtils.mkpath("/path/to/dir", :mode => 0755)
-    assert_kind_of FakeDir, FileSystem.fs['path']['to']['dir']
+    FileUtils.mkpath('/path/to/dir', mode: 0755)
+    assert_kind_of FakeFS::FakeDir, FakeFS::FileSystem.fs['path']['to']['dir']
   end
 
   def test_can_create_directories_with_mkdirs
-    FileUtils.makedirs("/path/to/dir")
-    assert_kind_of FakeDir, FileSystem.fs['path']['to']['dir']
+    FileUtils.makedirs('/path/to/dir')
+    assert_kind_of FakeFS::FakeDir, FakeFS::FileSystem.fs['path']['to']['dir']
   end
 
   def test_can_create_directories_with_mkdirs_and_options
-    FileUtils.makedirs("/path/to/dir", :mode => 0755)
-    assert_kind_of FakeDir, FileSystem.fs['path']['to']['dir']
+    FileUtils.makedirs('/path/to/dir', mode: 0755)
+    assert_kind_of FakeFS::FakeDir, FakeFS::FileSystem.fs['path']['to']['dir']
   end
 
   def test_unlink_errors_on_file_not_found
-    assert_raise Errno::ENOENT do
-      FileUtils.rm("/foo")
+    assert_raises Errno::ENOENT do
+      FileUtils.rm('/foo')
     end
   end
 
   def test_unlink_doesnt_error_on_file_not_found_when_forced
-    assert_nothing_raised do
-      FileUtils.rm("/foo", :force => true)
-    end
+    FileUtils.rm('/foo', force: true)
+  end
+
+  def test_unlink_doesnt_error_on_file_not_found_with_rm_rf
+    FileUtils.rm_rf('/foo')
   end
 
   def test_can_delete_directories
-    FileUtils.mkdir_p("/path/to/dir")
-    FileUtils.rmdir("/path/to/dir")
-    assert File.exists?("/path/to/")
-    assert File.exists?("/path/to/dir") == false
+    FileUtils.mkdir_p('/path/to/dir')
+    FileUtils.rmdir('/path/to/dir')
+    assert File.exist?('/path/to/')
+    assert File.exist?('/path/to/dir') == false
   end
 
   def test_can_delete_multiple_files
-    FileUtils.touch(["foo", "bar"])
-    FileUtils.rm(["foo", "bar"])
-    assert File.exists?("foo") == false
-    assert File.exists?("bar") == false
+    FileUtils.touch(%w(foo bar))
+    FileUtils.rm(%w(foo bar))
+    assert File.exist?('foo') == false
+    assert File.exist?('bar') == false
+  end
+
+  def test_aliases_exist
+    assert File.respond_to?(:unlink)
+    assert FileUtils.respond_to?(:rm_f)
+    assert FileUtils.respond_to?(:rm_r)
+    assert FileUtils.respond_to?(:rm)
+    assert FileUtils.respond_to?(:symlink)
+    assert FileUtils.respond_to?(:move)
+    assert FileUtils.respond_to?(:copy)
+    assert FileUtils.respond_to?(:remove)
+    assert FileUtils.respond_to?(:rmtree)
+    assert FileUtils.respond_to?(:safe_unlink)
+    assert FileUtils.respond_to?(:remove_entry_secure)
+    assert FileUtils.respond_to?(:cmp)
+    assert FileUtils.respond_to?(:identical?)
   end
 
   def test_knows_directories_exist
-    FileUtils.mkdir_p(path = "/path/to/dir")
-    assert File.exists?(path)
+    FileUtils.mkdir_p(path = '/path/to/dir')
+    assert File.exist?(path)
   end
 
   def test_knows_directories_are_directories
-    FileUtils.mkdir_p(path = "/path/to/dir")
+    FileUtils.mkdir_p(path = '/path/to/dir')
     assert File.directory?(path)
   end
 
   def test_knows_directories_are_directories_with_periods
-    FileUtils.mkdir_p(period_path = "/path/to/periodfiles/one.one")
-    FileUtils.mkdir("/path/to/periodfiles/one-one")
+    FileUtils.mkdir_p(period_path = '/path/to/periodfiles/one.one')
+    FileUtils.mkdir('/path/to/periodfiles/one-one')
 
     assert File.directory?(period_path)
   end
 
   def test_knows_symlink_directories_are_directories
-    FileUtils.mkdir_p(path = "/path/to/dir")
+    FileUtils.mkdir_p(path = '/path/to/dir')
     FileUtils.ln_s path, sympath = '/sympath'
     assert File.directory?(sympath)
   end
@@ -120,25 +187,30 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_doesnt_overwrite_existing_directories
-    FileUtils.mkdir_p(path = "/path/to/dir")
-    assert File.exists?(path)
-    FileUtils.mkdir_p("/path/to")
-    assert File.exists?(path)
+    FileUtils.mkdir_p(path = '/path/to/dir')
+    assert File.exist?(path)
+    FileUtils.mkdir_p('/path/to')
+    assert File.exist?(path)
     assert_raises Errno::EEXIST do
-      FileUtils.mkdir("/path/to")
+      FileUtils.mkdir('/path/to')
     end
-    assert File.exists?(path)
+    assert File.exist?(path)
+  end
+
+  def test_file_utils_mkdir_takes_options
+    FileUtils.mkdir('/foo', some: :option)
+    assert File.exist?('/foo')
   end
 
   def test_symlink_with_missing_refferent_does_not_exist
     File.symlink('/foo', '/bar')
-    assert !File.exists?('/bar')
+    refute File.exist?('/bar')
   end
 
   def test_can_create_symlinks
-    FileUtils.mkdir_p(target = "/path/to/target")
-    FileUtils.ln_s(target, "/path/to/link")
-    assert_kind_of FakeSymlink, FileSystem.fs['path']['to']['link']
+    FileUtils.mkdir_p(target = '/path/to/target')
+    FileUtils.ln_s(target, '/path/to/link')
+    assert_kind_of FakeFS::FakeSymlink, FakeFS::FileSystem.fs['path']['to']['link']
 
     assert_raises(Errno::EEXIST) do
       FileUtils.ln_s(target, '/path/to/link')
@@ -146,244 +218,246 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_can_force_creation_of_symlinks
-    FileUtils.mkdir_p(target = "/path/to/first/target")
-    FileUtils.ln_s(target, "/path/to/link")
-    assert_kind_of FakeSymlink, FileSystem.fs['path']['to']['link']
-    FileUtils.ln_s(target, '/path/to/link', :force => true)
+    FileUtils.mkdir_p(target = '/path/to/first/target')
+    FileUtils.ln_s(target, '/path/to/link')
+    assert_kind_of FakeFS::FakeSymlink, FakeFS::FileSystem.fs['path']['to']['link']
+    FileUtils.ln_s(target, '/path/to/link', force: true)
   end
 
   def test_create_symlink_using_ln_sf
-    FileUtils.mkdir_p(target = "/path/to/first/target")
-    FileUtils.ln_s(target, "/path/to/link")
-    assert_kind_of FakeSymlink, FileSystem.fs['path']['to']['link']
+    FileUtils.mkdir_p(target = '/path/to/first/target')
+    FileUtils.ln_s(target, '/path/to/link')
+    assert_kind_of FakeFS::FakeSymlink, FakeFS::FileSystem.fs['path']['to']['link']
     FileUtils.ln_sf(target, '/path/to/link')
   end
 
   def test_can_follow_symlinks
-    FileUtils.mkdir_p(target = "/path/to/target")
-    FileUtils.ln_s(target, link = "/path/to/symlink")
+    FileUtils.mkdir_p(target = '/path/to/target')
+    FileUtils.ln_s(target, link = '/path/to/symlink')
     assert_equal target, File.readlink(link)
   end
 
   def test_symlinks_in_different_directories
-    FileUtils.mkdir_p("/path/to/bar")
-    FileUtils.mkdir_p(target = "/path/to/foo/target")
+    FileUtils.mkdir_p('/path/to/bar')
+    FileUtils.mkdir_p(target = '/path/to/foo/target')
 
-    FileUtils.ln_s(target, link = "/path/to/bar/symlink")
+    FileUtils.ln_s(target, link = '/path/to/bar/symlink')
     assert_equal target, File.readlink(link)
   end
 
   def test_symlink_with_relative_path_exists
-    FileUtils.touch("/file")
-    FileUtils.mkdir_p("/a/b")
-    FileUtils.ln_s("../../file", link = "/a/b/symlink")
+    FileUtils.touch('/file')
+    FileUtils.mkdir_p('/a/b')
+    FileUtils.ln_s('../../file', '/a/b/symlink')
     assert File.exist?('/a/b/symlink')
   end
 
   def test_symlink_with_relative_path_and_nonexistant_file_does_not_exist
-    FileUtils.touch("/file")
-    FileUtils.mkdir_p("/a/b")
-    FileUtils.ln_s("../../file_foo", link = "/a/b/symlink")
-    assert !File.exist?('/a/b/symlink')
+    FileUtils.touch('/file')
+    FileUtils.mkdir_p('/a/b')
+    FileUtils.ln_s('../../file_foo', '/a/b/symlink')
+    refute File.exist?('/a/b/symlink')
   end
 
   def test_symlink_with_relative_path_has_correct_target
-    FileUtils.touch("/file")
-    FileUtils.mkdir_p("/a/b")
-    FileUtils.ln_s("../../file", link = "/a/b/symlink")
-    assert_equal "../../file", File.readlink(link)
+    FileUtils.touch('/file')
+    FileUtils.mkdir_p('/a/b')
+    FileUtils.ln_s('../../file', link = '/a/b/symlink')
+    assert_equal '../../file', File.readlink(link)
   end
 
   def test_symlinks_to_symlinks
-    FileUtils.mkdir_p(target = "/path/to/foo/target")
-    FileUtils.mkdir_p("/path/to/bar")
-    FileUtils.mkdir_p("/path/to/bar2")
+    FileUtils.mkdir_p(target = '/path/to/foo/target')
+    FileUtils.mkdir_p('/path/to/bar')
+    FileUtils.mkdir_p('/path/to/bar2')
 
-    FileUtils.ln_s(target, link1 = "/path/to/bar/symlink")
-    FileUtils.ln_s(link1, link2 = "/path/to/bar2/symlink")
+    FileUtils.ln_s(target, link1 = '/path/to/bar/symlink')
+    FileUtils.ln_s(link1, link2 = '/path/to/bar2/symlink')
     assert_equal link1, File.readlink(link2)
   end
 
   def test_symlink_to_symlinks_should_raise_error_if_dir_doesnt_exist
-    FileUtils.mkdir_p(target = "/path/to/foo/target")
+    FileUtils.mkdir_p(target = '/path/to/foo/target')
 
-    assert !Dir.exists?("/path/to/bar")
+    refute Dir.exist?('/path/to/bar')
 
-    assert_raise Errno::ENOENT do
-      FileUtils.ln_s(target, "/path/to/bar/symlink")
+    assert_raises Errno::ENOENT do
+      FileUtils.ln_s(target, '/path/to/bar/symlink')
     end
   end
 
   def test_knows_symlinks_are_symlinks
-    FileUtils.mkdir_p(target = "/path/to/target")
-    FileUtils.ln_s(target, link = "/path/to/symlink")
+    FileUtils.mkdir_p(target = '/path/to/target')
+    FileUtils.ln_s(target, link = '/path/to/symlink')
     assert File.symlink?(link)
   end
 
   def test_can_create_files_in_current_dir
     path = 'file.txt'
     File.open(path, 'w') do |f|
-      f.write "Yatta!"
+      f.write 'Yatta!'
     end
 
-    assert File.exists?(path)
+    assert File.exist?(path)
     assert File.readable?(path)
     assert File.writable?(path)
   end
 
+  def test_nothing_is_sticky
+    refute File.sticky?('/')
+  end
+
   def test_can_create_files_in_existing_dir
-    FileUtils.mkdir_p "/path/to"
-    path = "/path/to/file.txt"
+    FileUtils.mkdir_p '/path/to'
+    path = '/path/to/file.txt'
 
     File.open(path, 'w') do |f|
-      f.write "Yatta!"
+      f.write 'Yatta!'
     end
 
-    assert File.exists?(path)
+    assert File.exist?(path)
     assert File.readable?(path)
     assert File.writable?(path)
   end
 
   def test_raises_ENOENT_trying_to_create_files_in_nonexistent_dir
-    path = "/path/to/file.txt"
+    path = '/path/to/file.txt'
 
-    assert_raises(Errno::ENOENT) {
+    assert_raises(Errno::ENOENT) do
       File.open(path, 'w') do |f|
-        f.write "Yatta!"
+        f.write 'Yatta!'
       end
-    }
+    end
   end
 
   def test_raises_ENOENT_trying_to_create_files_in_relative_nonexistent_dir
-    FileUtils.mkdir_p "/some/path"
+    FileUtils.mkdir_p '/some/path'
 
-    Dir.chdir("/some/path") {
-      assert_raises(Errno::ENOENT) {
-        File.open("../foo") {|f| f.write "moo" }
-      }
-    }
+    Dir.chdir('/some/path') do
+      assert_raises(Errno::ENOENT) do
+        File.open('../foo') { |f| f.write 'moo' }
+      end
+    end
   end
 
   def test_raises_ENOENT_trying_to_create_files_in_obscured_nonexistent_dir
-    FileUtils.mkdir_p "/some/path"
+    FileUtils.mkdir_p '/some/path'
 
-    assert_raises(Errno::ENOENT) {
-      File.open("/some/path/../foo") {|f| f.write "moo" }
-    }
+    assert_raises(Errno::ENOENT) do
+      File.open('/some/path/../foo') { |f| f.write 'moo' }
+    end
   end
 
   def test_raises_ENOENT_trying_to_create_tilde_referenced_nonexistent_dir
-    path = "~/fakefs_test_#{$$}_0000"
+    path = "~/fakefs_test_#{$PID}_0000"
 
-    while File.exist? path
-      path = path.succ
-    end
+    path = path.succ while File.exist? path
 
-    assert_raises(Errno::ENOENT) {
-      File.open("#{path}/foo") {|f| f.write "moo" }
-    }
+    assert_raises(Errno::ENOENT) do
+      File.open("#{path}/foo") { |f| f.write 'moo' }
+    end
   end
 
   def test_raises_EISDIR_if_trying_to_open_existing_directory_name
-    path = "/path/to"
+    path = '/path/to'
 
     FileUtils.mkdir_p path
 
-    assert_raises(Errno::EISDIR) {
+    assert_raises(Errno::EISDIR) do
       File.open(path, 'w') do |f|
-        f.write "Yatta!"
+        f.write 'Yatta!'
       end
-    }
+    end
   end
 
   def test_can_create_files_with_bitmasks
-    FileUtils.mkdir_p("/path/to")
+    FileUtils.mkdir_p('/path/to')
 
     path = '/path/to/file.txt'
     File.open(path, File::RDWR | File::CREAT) do |f|
-      f.write "Yatta!"
+      f.write 'Yatta!'
     end
 
-    assert File.exists?(path)
+    assert File.exist?(path)
     assert File.readable?(path)
     assert File.writable?(path)
   end
 
   def test_file_opens_in_read_only_mode
-    File.open("foo", "w") { |f| f << "foo" }
+    File.open('foo', 'w') { |f| f << 'foo' }
 
-    f = File.open("foo")
+    f = File.open('foo')
 
     assert_raises(IOError) do
-      f << "bar"
+      f << 'bar'
     end
   end
 
   def test_file_opens_in_read_only_mode_with_bitmasks
-    File.open("foo", "w") { |f| f << "foo" }
+    File.open('foo', 'w') { |f| f << 'foo' }
 
-    f = File.open("foo", File::RDONLY)
+    f = File.open('foo', File::RDONLY)
 
     assert_raises(IOError) do
-      f << "bar"
+      f << 'bar'
     end
   end
 
   def test_file_opens_in_invalid_mode
-    FileUtils.touch("foo")
+    FileUtils.touch('foo')
 
     assert_raises(ArgumentError) do
-      File.open("foo", "an_illegal_mode")
+      File.open('foo', 'an_illegal_mode')
     end
   end
 
   def test_raises_error_when_cannot_find_file_in_read_mode
     assert_raises(Errno::ENOENT) do
-      File.open("does_not_exist", "r")
+      File.open('does_not_exist', 'r')
     end
   end
 
   def test_raises_error_when_cannot_find_file_in_read_write_mode
     assert_raises(Errno::ENOENT) do
-      File.open("does_not_exist", "r+")
+      File.open('does_not_exist', 'r+')
     end
   end
 
   def test_creates_files_in_write_only_mode
-    File.open("foo", "w")
-    assert File.exists?("foo")
+    File.open('foo', 'w')
+    assert File.exist?('foo')
   end
 
   def test_creates_files_in_write_only_mode_with_bitmasks
-    File.open("foo", File::WRONLY | File::CREAT)
-    assert File.exists?("foo")
+    File.open('foo', File::WRONLY | File::CREAT)
+    assert File.exist?('foo')
   end
 
   def test_raises_in_write_only_mode_without_create_bitmask
     assert_raises(Errno::ENOENT) do
-      File.open("foo", File::WRONLY)
+      File.open('foo', File::WRONLY)
     end
   end
 
   def test_creates_files_in_read_write_truncate_mode
-    File.open("foo", "w+")
-    assert File.exists?("foo")
+    File.open('foo', 'w+')
+    assert File.exist?('foo')
   end
 
   def test_creates_files_in_append_write_only
-    File.open("foo", "a")
-    assert File.exists?("foo")
+    File.open('foo', 'a')
+    assert File.exist?('foo')
   end
 
   def test_creates_files_in_append_read_write
-    File.open("foo", "a+")
-    assert File.exists?("foo")
+    File.open('foo', 'a+')
+    assert File.exist?('foo')
   end
 
   def test_file_in_write_only_raises_error_when_reading
-    FileUtils.touch("foo")
+    FileUtils.touch('foo')
 
-    f = File.open("foo", "w")
+    f = File.open('foo', 'w')
 
     assert_raises(IOError) do
       f.read
@@ -391,25 +465,21 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_file_in_write_mode_truncates_existing_file
-    File.open("foo", "w") { |f| f << "contents" }
-
-    f = File.open("foo", "w")
-
-    assert_equal "", File.read("foo")
+    File.open('foo', 'w') { |f| f << 'contents' }
+    File.open('foo', 'w')
+    assert_equal '', File.read('foo')
   end
 
   def test_file_in_read_write_truncation_mode_truncates_file
-    File.open("foo", "w") { |f| f << "foo" }
-
-    f = File.open("foo", "w+")
-
-    assert_equal "", File.read("foo")
+    File.open('foo', 'w') { |f| f << 'foo' }
+    File.open('foo', 'w+')
+    assert_equal '', File.read('foo')
   end
 
   def test_file_in_append_write_only_raises_error_when_reading
-    FileUtils.touch("foo")
+    FileUtils.touch('foo')
 
-    f = File.open("foo", "a")
+    f = File.open('foo', 'a')
 
     assert_raises(IOError) do
       f.read
@@ -419,10 +489,10 @@ class FakeFSTest < Test::Unit::TestCase
   def test_can_read_files_once_written
     path = 'file.txt'
     File.open(path, 'w') do |f|
-      f.write "Yatta!"
+      f.write 'Yatta!'
     end
 
-    assert_equal "Yatta!", File.read(path)
+    assert_equal 'Yatta!', File.read(path)
   end
 
   def test_file_read_accepts_hashes
@@ -431,7 +501,19 @@ class FakeFSTest < Test::Unit::TestCase
       f.write 'Yatta!'
     end
 
-    assert_nothing_raised { File.read(path, :mode => 'r:UTF-8:-') }
+    # nothing raised
+    File.read(path, mode: 'r:UTF-8:-')
+  end
+
+  def test_file_read_respects_args
+    path = 'file.txt'
+    File.open(path, 'w') do |f|
+      f.write 'Yatta!'
+    end
+
+    assert_equal 'Ya', File.read(path, 2)
+    assert_equal 'at', File.read(path, 2, 1)
+    assert_equal 'atta!', File.read(path, nil, 1)
   end
 
   def test_can_write_to_files
@@ -443,18 +525,18 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_raises_error_when_opening_with_binary_mode_only
-    assert_raise ArgumentError do
-      File.open("/foo", "b")
+    assert_raises ArgumentError do
+      File.open('/foo', 'b')
     end
   end
 
   def test_can_open_file_in_binary_mode
-    File.open("foo", "wb") { |x| x << "a" }
-    assert_equal "a", File.read("foo")
+    File.open('foo', 'wb') { |x| x << 'a' }
+    assert_equal 'a', File.read('foo')
   end
 
   def test_can_chunk_io_when_reading
-    FileUtils.mkdir_p "/path/to"
+    FileUtils.mkdir_p '/path/to'
     path = '/path/to/file.txt'
     File.open(path, 'w') do |f|
       f << 'Yada Yada'
@@ -475,13 +557,21 @@ class FakeFSTest < Test::Unit::TestCase
     assert_equal 9, File.size(path)
   end
 
+  def test_can_get_correct_size_for_files_with_multibyte_characters
+    path = 'file.txt'
+    File.open(path, 'wb') do |f|
+      f << "Y\xC3\xA1da"
+    end
+    assert_equal 5, File.size(path)
+  end
+
   def test_can_check_if_file_has_size?
     path = 'file.txt'
     File.open(path, 'w') do |f|
       f << 'Yada Yada'
     end
-    assert File.size?(path)
-    assert_nil File.size?("other.txt")
+    assert_equal 9, File.size?(path)
+    assert_nil File.size?('other.txt')
   end
 
   def test_can_check_size_of_empty_file
@@ -489,15 +579,54 @@ class FakeFSTest < Test::Unit::TestCase
     File.open(path, 'w') do |f|
       f << ''
     end
-    assert_nil File.size?("file.txt")
+    assert_nil File.size?('file.txt')
+  end
+
+  def test_zero_on_empty_file
+    path = 'file.txt'
+    File.open(path, 'w') do |f|
+      f << ''
+    end
+    assert_equal true, File.zero?(path)
+  end
+
+  def test_zero_on_non_empty_file
+    path = 'file.txt'
+    File.open(path, 'w') do |f|
+      f << 'Not empty'
+    end
+    assert_equal false, File.zero?(path)
+  end
+
+  def test_zero_on_non_existent_file
+    path = 'file_does_not_exist.txt'
+    assert_equal false, File.zero?(path)
   end
 
   def test_raises_error_on_mtime_if_file_does_not_exist
-    assert_raise Errno::ENOENT do
+    assert_raises Errno::ENOENT do
       File.mtime('/path/to/file.txt')
     end
   end
 
+  if RUBY_VERSION >= '1.9'
+    def test_can_set_mtime_on_new_file_touch_with_param
+      time = Time.new(2002, 10, 31, 2, 2, 2, '+02:00')
+      FileUtils.touch('foo.txt', mtime: time)
+
+      assert_equal File.mtime('foo.txt'), time
+    end
+
+    def test_can_set_mtime_on_existing_file_touch_with_param
+      FileUtils.touch('foo.txt')
+
+      time = Time.new(2002, 10, 31, 2, 2, 2, '+02:00')
+      FileUtils.touch('foo.txt', mtime: time)
+
+      assert_equal File.mtime('foo.txt'), time
+    end
+  end
+
   def test_can_return_mtime_on_existing_file
     path = 'file.txt'
     File.open(path, 'w') do |f|
@@ -507,40 +636,40 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_raises_error_on_ctime_if_file_does_not_exist
-    assert_raise Errno::ENOENT do
+    assert_raises Errno::ENOENT do
       File.ctime('file.txt')
     end
   end
 
   def test_can_return_ctime_on_existing_file
-    File.open("foo", "w") { |f| f << "some content" }
+    File.open('foo', 'w') { |f| f << 'some content' }
     assert File.ctime('foo').is_a?(Time)
   end
 
   def test_raises_error_on_atime_if_file_does_not_exist
-    assert_raise Errno::ENOENT do
+    assert_raises Errno::ENOENT do
       File.atime('file.txt')
     end
   end
 
   def test_can_return_atime_on_existing_file
-    File.open("foo", "w") { |f| f << "some content" }
+    File.open('foo', 'w') { |f| f << 'some content' }
     assert File.atime('foo').is_a?(Time)
   end
 
   def test_ctime_mtime_and_atime_are_equal_for_new_files
     FileUtils.touch('foo')
 
-    ctime = File.ctime("foo")
-    mtime = File.mtime("foo")
-    atime = File.atime("foo")
+    ctime = File.ctime('foo')
+    mtime = File.mtime('foo')
+    atime = File.atime('foo')
     assert ctime.is_a?(Time)
     assert mtime.is_a?(Time)
     assert atime.is_a?(Time)
     assert_equal ctime, mtime
     assert_equal ctime, atime
 
-    File.open("foo", "r") do |f|
+    File.open('foo', 'r') do |f|
       assert_equal ctime, f.ctime
       assert_equal mtime, f.mtime
       assert_equal atime, f.atime
@@ -548,10 +677,10 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_ctime_mtime_and_atime_are_equal_for_new_directories
-    FileUtils.mkdir_p("foo")
-    ctime = File.ctime("foo")
-    mtime = File.mtime("foo")
-    atime = File.atime("foo")
+    FileUtils.mkdir_p('foo')
+    ctime = File.ctime('foo')
+    mtime = File.mtime('foo')
+    atime = File.atime('foo')
     assert ctime.is_a?(Time)
     assert mtime.is_a?(Time)
     assert atime.is_a?(Time)
@@ -560,37 +689,37 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_file_ctime_is_equal_to_file_stat_ctime
-    File.open("foo", "w") { |f| f << "some content" }
-    assert_equal File.stat("foo").ctime, File.ctime("foo")
+    File.open('foo', 'w') { |f| f << 'some content' }
+    assert_equal File.stat('foo').ctime, File.ctime('foo')
   end
 
   def test_directory_ctime_is_equal_to_directory_stat_ctime
-    FileUtils.mkdir_p("foo")
-    assert_equal File.stat("foo").ctime, File.ctime("foo")
+    FileUtils.mkdir_p('foo')
+    assert_equal File.stat('foo').ctime, File.ctime('foo')
   end
 
   def test_file_mtime_is_equal_to_file_stat_mtime
-    File.open("foo", "w") { |f| f << "some content" }
-    assert_equal File.stat("foo").mtime, File.mtime("foo")
+    File.open('foo', 'w') { |f| f << 'some content' }
+    assert_equal File.stat('foo').mtime, File.mtime('foo')
   end
 
   def test_directory_mtime_is_equal_to_directory_stat_mtime
-    FileUtils.mkdir_p("foo")
-    assert_equal File.stat("foo").mtime, File.mtime("foo")
+    FileUtils.mkdir_p('foo')
+    assert_equal File.stat('foo').mtime, File.mtime('foo')
   end
 
   def test_file_atime_is_equal_to_file_stat_atime
-    File.open("foo", "w") { |f| f << "some content" }
-    assert_equal File.stat("foo").atime, File.atime("foo")
+    File.open('foo', 'w') { |f| f << 'some content' }
+    assert_equal File.stat('foo').atime, File.atime('foo')
   end
 
   def test_directory_atime_is_equal_to_directory_stat_atime
-    FileUtils.mkdir_p("foo")
-    assert_equal File.stat("foo").atime, File.atime("foo")
+    FileUtils.mkdir_p('foo')
+    assert_equal File.stat('foo').atime, File.atime('foo')
   end
 
   def test_utime_raises_error_if_path_does_not_exist
-    assert_raise Errno::ENOENT do
+    assert_raises Errno::ENOENT do
       File.utime(Time.now, Time.now, '/path/to/file.txt')
     end
   end
@@ -619,9 +748,9 @@ class FakeFSTest < Test::Unit::TestCase
   def test_file_a_time_updated_when_file_is_read
     old_atime = Time.now - 300
 
-    path = "file.txt"
-    File.open(path, "w") do |f|
-      f << "Hello"
+    path = 'file.txt'
+    File.open(path, 'w') do |f|
+      f << 'Hello'
     end
 
     File.utime(old_atime, File.mtime(path), path)
@@ -634,11 +763,29 @@ class FakeFSTest < Test::Unit::TestCase
   def test_can_read_with_File_readlines
     path = 'file.txt'
     File.open(path, 'w') do |f|
-      f.puts "Yatta!", "Gatta!"
-      f.puts ["woot","toot"]
+      f.puts 'Yatta!', 'Gatta!'
+      f.puts %w(woot toot)
+    end
+
+    assert_equal ["Yatta!\n", "Gatta!\n", "woot\n", "toot\n"], File.readlines(path)
+  end
+
+  def test_can_read_with_File_readlines_and_only_empty_lines
+    path = 'file.txt'
+    File.open(path, 'w') do |f|
+      f.write "\n"
+    end
+
+    assert_equal ["\n"], File.readlines(path)
+  end
+
+  def test_can_read_with_File_readlines_and_new_lines
+    path = 'file.txt'
+    File.open(path, 'w') do |f|
+      f.write "this\nis\na\ntest\n"
     end
 
-    assert_equal %w(Yatta! Gatta! woot toot), File.readlines(path)
+    assert_equal ["this\n", "is\n", "a\n", "test\n"], File.readlines(path)
   end
 
   def test_File_close_disallows_further_access
@@ -646,7 +793,7 @@ class FakeFSTest < Test::Unit::TestCase
     file = File.open(path, 'w')
     file.write 'Yada'
     file.close
-    assert_raise IOError do
+    assert_raises IOError do
       file.read
     end
   end
@@ -656,66 +803,114 @@ class FakeFSTest < Test::Unit::TestCase
     file = File.open(path, 'w')
     file.write 'Yada'
     file.close
-    assert_raise IOError do
-      file << "foo"
+    assert_raises IOError do
+      file << 'foo'
     end
   end
 
   def test_can_read_from_file_objects
     path = 'file.txt'
     File.open(path, 'w') do |f|
-      f.write "Yatta!"
+      f.write 'Yatta!'
     end
 
-    assert_equal "Yatta!", File.new(path).read
+    assert_equal 'Yatta!', File.new(path).read
   end
 
-  if RUBY_VERSION >= "1.9"
+  if RUBY_VERSION >= '1.9'
     def test_file_object_has_default_external_encoding
-      Encoding.default_external = "UTF-8"
+      Encoding.default_external = 'UTF-8'
       path = 'file.txt'
-      File.open(path, 'w'){|f| f.write 'Yatta!' }
-      assert_equal "UTF-8", File.new(path).read.encoding.name
+      File.open(path, 'w') { |f| f.write 'Yatta!' }
+      assert_equal 'UTF-8', File.new(path).read.encoding.name
     end
   end
 
   def test_file_object_initialization_with_mode_in_hash_parameter
-    assert_nothing_raised do
-      File.open("file.txt", {:mode => "w"}){ |f| f.write 'Yatta!' }
-    end
+    File.open('file.txt', mode: 'w') { |f| f.write 'Yatta!' }
+  end
+
+  def test_file_object_initialization_with_brackets_in_filename
+    filename = 'bracket[1](2).txt'
+    expected_contents = 'Yokudekimashita'
+    # nothing raised
+    File.open(filename, mode: 'w') { |f| f.write "#{expected_contents}" }
+    the_file = Dir['/*']
+    assert_equal the_file.length, 1
+    assert_equal the_file[0], "/#{filename}"
+    contents = File.open("/#{filename}").read
+    assert_equal contents, expected_contents
+  end
+
+  def test_file_object_initialization_with_brackets_in_filename
+    filename = "\u65e5\u672c\u8a9e.txt"
+    expected_contents = 'Yokudekimashita'
+    # nothing raised
+    File.open(filename,  mode: 'w') { |f| f.write "#{expected_contents}" }
+    contents = File.open("/#{filename}").read
+    assert_equal contents, expected_contents
   end
 
   def test_file_read_errors_appropriately
-    assert_raise Errno::ENOENT do
+    assert_raises Errno::ENOENT do
       File.read('anything')
     end
   end
 
+  def test_file_read_errors_on_directory
+    FileUtils.mkdir_p('a_directory')
+
+    assert_raises Errno::EISDIR do
+      File.read('a_directory')
+    end
+  end
+
   def test_knows_files_are_files
     path = 'file.txt'
     File.open(path, 'w') do |f|
-      f.write "Yatta!"
+      f.write 'Yatta!'
     end
 
     assert File.file?(path)
   end
 
+  def test_size_returns_size
+    first_file = 'first.txt'
+    File.open(first_file, 'w') do |f|
+      f.write '12345678'
+    end
+
+    assert_equal File.size?(first_file), 8
+
+    File.open(first_file, 'w') do |f|
+      f.write 'abcd'
+    end
+
+    assert_equal File.size?(first_file), 4
+
+    second_file = 'second.txt'
+    File.open(second_file, 'w') do |f|
+      f.write '1'
+    end
+    assert_equal File.size?(second_file), 1
+  end
+
   def test_File_io_returns_self
-    f = File.open("foo", "w")
+    f = File.open('foo', 'w')
     assert_equal f, f.to_io
   end
 
   def test_File_to_i_is_alias_for_filno
-    f = File.open("foo", "w")
+    f = File.open('foo', 'w')
     assert_equal f.method(:to_i), f.method(:fileno)
   end
 
   def test_knows_symlink_files_are_files
     path = 'file.txt'
     File.open(path, 'w') do |f|
-      f.write "Yatta!"
+      f.write 'Yatta!'
     end
-    FileUtils.ln_s path, sympath='/sympath'
+    FileUtils.ln_s path, sympath = '/sympath'
 
     assert File.file?(sympath)
   end
@@ -724,19 +919,23 @@ class FakeFSTest < Test::Unit::TestCase
     assert_equal RealFile.file?('does/not/exist.txt'), File.file?('does/not/exist.txt')
   end
 
+  def test_executable_returns_false_for_non_existent_files
+    refute File.executable?('/does/not/exist')
+  end
+
   def test_can_chown_files
     good = 'file.txt'
     bad = 'nofile.txt'
-    File.open(good,'w') { |f| f.write "foo" }
+    File.open(good, 'w') { |f| f.write 'foo' }
     username = Etc.getpwuid(Process.uid).name
     groupname = Etc.getgrgid(Process.gid).name
 
-    out = FileUtils.chown(1337, 1338, good, :verbose => true)
+    out = FileUtils.chown(1337, 1338, good, verbose: true)
     assert_equal [good], out
     assert_equal File.stat(good).uid, 1337
     assert_equal File.stat(good).gid, 1338
     assert_raises(Errno::ENOENT) do
-      FileUtils.chown(username, groupname, bad, :verbose => true)
+      FileUtils.chown(username, groupname, bad, verbose: true)
     end
 
     assert_equal [good], FileUtils.chown(username, groupname, good)
@@ -779,12 +978,13 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_can_chmod_files
-    good = "file.txt"
-    bad = "nofile.txt"
+    good = 'file.txt'
+    bad = 'nofile.txt'
     FileUtils.touch(good)
 
-    assert_equal [good], FileUtils.chmod(0600, good, :verbose => true)
+    assert_equal [good], FileUtils.chmod(0600, good, verbose: true)
     assert_equal File.stat(good).mode, 0100600
+    assert_equal File.executable?(good), false
     assert_raises(Errno::ENOENT) do
       FileUtils.chmod(0600, bad)
     end
@@ -800,35 +1000,47 @@ class FakeFSTest < Test::Unit::TestCase
     assert_raises(Errno::ENOENT) do
       FileUtils.chmod(0644, bad)
     end
+
+    assert_equal [good], FileUtils.chmod(0744, [good])
+    assert_equal File.executable?(good), true
+
+    # This behaviour is unimplemented, the spec below is only to show that it
+    # is a deliberate YAGNI omission.
+    assert_equal [good], FileUtils.chmod(0477, [good])
+    assert_equal File.executable?(good), false
   end
 
   def test_can_chmod_R_files
-    FileUtils.mkdir_p "/path/sub"
-    FileUtils.touch "/path/file1"
-    FileUtils.touch "/path/sub/file2"
+    FileUtils.mkdir_p '/path/sub'
+    FileUtils.touch '/path/file1'
+    FileUtils.touch '/path/sub/file2'
 
-    assert_equal ["/path"], FileUtils.chmod_R(0600, "/path")
-    assert_equal File.stat("/path").mode, 0100600
-    assert_equal File.stat("/path/file1").mode, 0100600
-    assert_equal File.stat("/path/sub").mode, 0100600
-    assert_equal File.stat("/path/sub/file2").mode, 0100600
+    assert_equal ['/path'], FileUtils.chmod_R(0600, '/path')
+    assert_equal File.stat('/path').mode, 0100600
+    assert_equal File.stat('/path/file1').mode, 0100600
+    assert_equal File.stat('/path/sub').mode, 0100600
+    assert_equal File.stat('/path/sub/file2').mode, 0100600
 
-    FileUtils.mkdir_p "/path2"
-    FileUtils.touch "/path2/hej"
-    assert_equal ["/path2"], FileUtils.chmod_R(0600, "/path2")
+    FileUtils.mkdir_p '/path2'
+    FileUtils.touch '/path2/hej'
+    assert_equal ['/path2'], FileUtils.chmod_R(0600, '/path2')
   end
 
   def test_dir_globs_paths
     FileUtils.mkdir_p '/path'
     File.open('/path/foo', 'w') { |f| f.write 'foo' }
     File.open('/path/foobar', 'w') { |f| f.write 'foo' }
+    File.open('/path/.bar', 'w') { |f| f.write 'foo' }
 
     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'], Dir['/path']
+    assert_equal ['/path/.bar'], Dir['**/{.*}']
+    assert_equal ['/path/.bar'], Dir['/path**/{.*}']
+    assert_equal ['/path/.bar'], Dir['/path/{.*}']
     assert_equal %w( /path/bar /path/bar2 /path/foo /path/foobar ), Dir['/path/*']
 
     assert_equal ['/path/bar/baz'], Dir['/path/bar/*']
@@ -860,6 +1072,34 @@ class FakeFSTest < Test::Unit::TestCase
     end
   end
 
+  def test_file_utils_cp_allows_verbose_option
+    File.open('foo', 'w') { |f| f << 'TEST' }
+    assert_equal "cp foo bar\n", capture_stderr { FileUtils.cp 'foo', 'bar', verbose: true }
+  end
+
+  def test_file_utils_cp_allows_noop_option
+    File.open('foo', 'w') { |f| f << 'TEST' }
+    FileUtils.cp 'foo', 'bar', noop: true
+    refute File.exist?('bar'), 'does not actually copy'
+  end
+
+  def test_file_utils_cp_raises_on_invalid_option
+    assert_raises ArgumentError do
+      FileUtils.cp 'foo', 'bar', whatisthis: "I don't know"
+    end
+  end
+
+  def test_file_utils_cp_r_allows_verbose_option
+    FileUtils.touch '/foo'
+    assert_equal "cp -r /foo /bar\n", capture_stderr { FileUtils.cp_r '/foo', '/bar', verbose: true }
+  end
+
+  def test_file_utils_cp_r_allows_noop_option
+    FileUtils.touch '/foo'
+    FileUtils.cp_r '/foo', '/bar', noop: true
+    refute File.exist?('/bar'), 'does not actually copy'
+  end
+
   def test_dir_glob_handles_root
     FileUtils.mkdir_p '/path'
 
@@ -867,8 +1107,13 @@ class FakeFSTest < Test::Unit::TestCase
     assert_equal ['/'], Dir['/']
   end
 
+  def test_dir_glob_takes_optional_flags
+    FileUtils.touch '/foo'
+    assert_equal Dir.glob('/*', 0), ['/foo']
+  end
+
   def test_dir_glob_handles_recursive_globs
-    FileUtils.mkdir_p "/one/two/three"
+    FileUtils.mkdir_p '/one/two/three'
     File.open('/one/two/three/four.rb', 'w')
     File.open('/one/five.rb', 'w')
     assert_equal ['/one/five.rb', '/one/two/three/four.rb'], Dir['/one/**/*.rb']
@@ -877,13 +1122,19 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_dir_recursive_glob_ending_in_wildcards_returns_both_files_and_dirs
-    FileUtils.mkdir_p "/one/two/three"
+    FileUtils.mkdir_p '/one/two/three'
     File.open('/one/two/three/four.rb', 'w')
     File.open('/one/five.rb', 'w')
     assert_equal ['/one/five.rb', '/one/two', '/one/two/three', '/one/two/three/four.rb'], Dir['/one/**/*']
     assert_equal ['/one/five.rb', '/one/two'], Dir['/one/**']
   end
 
+  def test_dir_glob_ending_in_group_and_wildcard
+    FileUtils.mkdir_p '/tmp/python-3.4.1'
+    FileUtils.mkdir_p '/tmp/python-2.7.8'
+    assert_equal ['/tmp/python-2.7.8', '/tmp/python-3.4.1'], Dir.glob('/tmp/python-[0-9]*')
+  end
+
   def test_dir_glob_with_block
     FileUtils.touch('foo')
     FileUtils.touch('bar')
@@ -894,15 +1145,25 @@ class FakeFSTest < Test::Unit::TestCase
     assert_equal 2, yielded.size
   end
 
-  if RUBY_VERSION >= "1.9"
+  def test_copy_with_subdirectory
+    FileUtils.mkdir_p '/one/two/three/'
+    FileUtils.mkdir_p '/onebis/two/three/'
+    FileUtils.touch '/one/two/three/foo'
+    Dir.glob('/one/two/three/*') do |hook|
+      FileUtils.cp(hook, '/onebis/two/three/')
+    end
+    assert_equal ['/onebis/two/three/foo'], Dir['/onebis/two/three/*']
+  end
+
+  if RUBY_VERSION >= '1.9'
     def test_dir_home
       assert_equal RealDir.home, Dir.home
     end
   end
 
   def test_should_report_pos_as_0_when_opening
-    File.open("foo", "w") do |f|
-      f << "foobar"
+    File.open('foo', 'w') do |f|
+      f << 'foobar'
       f.rewind
 
       assert_equal 0, f.pos
@@ -910,8 +1171,8 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_should_report_pos_as_1_when_seeking_one_char
-    File.open("foo", "w") do |f|
-      f << "foobar"
+    File.open('foo', 'w') do |f|
+      f << 'foobar'
 
       f.rewind
       f.seek(1)
@@ -921,29 +1182,39 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_should_set_pos
-    File.open("foo", "w") do |f|
-      f << "foo"
+    File.open('foo', 'w') do |f|
+      f << 'foo'
     end
 
-    fp = File.open("foo", "r")
+    fp = File.open('foo', 'r')
     fp.pos = 1
 
     assert_equal 1, fp.pos
   end
 
   def test_should_set_pos_with_tell_method
-    File.open("foo", "w") do |f|
-      f << "foo"
+    File.open('foo', 'w') do |f|
+      f << 'foo'
     end
 
-    fp = File.open("foo", "r")
+    fp = File.open('foo', 'r')
     fp.tell = 1
 
     assert_equal 1, fp.pos
   end
 
+  OMITTED_FILE_METHODS = [
+    # omit methods from io/console
+    :raw, :raw!, :cooked, :cooked!,
+    :echo?, :echo=, :noecho,
+    :winsize, :winsize=,
+    :getch,
+    :iflush, :ioflush, :oflush,
+    :pathconf
+  ]
+
   def test_every_method_in_file_is_in_fake_fs_file
-    RealFile.instance_methods.each do |method_name|
+    (RealFile.instance_methods - OMITTED_FILE_METHODS).each do |method_name|
       assert File.instance_methods.include?(method_name), "#{method_name} method is not available in File :("
     end
   end
@@ -951,26 +1222,32 @@ class FakeFSTest < Test::Unit::TestCase
   def test_file_should_not_respond_to_string_io_unique_methods
     uniq_string_io_methods = StringIO.instance_methods - RealFile.instance_methods
     uniq_string_io_methods.each do |method_name|
-      assert !File.instance_methods.include?(method_name), "File responds to #{method_name}"
+      refute File.instance_methods.include?(method_name), "File responds to #{method_name}"
     end
   end
 
   def test_does_not_remove_methods_from_stringio
-    stringio = StringIO.new("foo")
+    stringio = StringIO.new('foo')
     assert stringio.respond_to?(:size)
   end
 
+  def test_is_not_a_stringio
+    File.open('foo', 'w') do |f|
+      refute f.is_a?(StringIO), 'File is not a StringIO'
+    end
+  end
+
   def test_chdir_changes_directories_like_a_boss
     # I know memes!
     FileUtils.mkdir_p '/path'
-    assert_equal '/', FileSystem.fs.name
+    assert_equal '/', FakeFS::FileSystem.fs.name
     assert_equal [], Dir.glob('/path/*')
     Dir.chdir '/path' do
-      File.open('foo', 'w') { |f| f.write 'foo'}
-      File.open('foobar', 'w') { |f| f.write 'foo'}
+      File.open('foo', 'w') { |f| f.write 'foo' }
+      File.open('foobar', 'w') { |f| f.write 'foo' }
     end
 
-    assert_equal '/', FileSystem.fs.name
+    assert_equal '/', FakeFS::FileSystem.fs.name
     assert_equal(['/path/foo', '/path/foobar'], Dir.glob('/path/*').sort)
 
     c = nil
@@ -985,8 +1262,8 @@ class FakeFSTest < Test::Unit::TestCase
     FileUtils.mkdir_p '/path'
 
     Dir.chdir '/path' do
-      File.open('foo', 'w') { |f| f.write 'foo'}
-      File.open('/foobar', 'w') { |f| f.write 'foo'}
+      File.open('foo', 'w') { |f| f.write 'foo' }
+      File.open('/foobar', 'w') { |f| f.write 'foo' }
     end
     assert_equal ['/path/foo'], Dir.glob('/path/*').sort
     assert_equal ['/foobar', '/path'], Dir.glob('/*').sort
@@ -1003,18 +1280,31 @@ class FakeFSTest < Test::Unit::TestCase
   def test_chdir_should_be_nestable
     FileUtils.mkdir_p '/path/me'
     Dir.chdir '/path' do
-      File.open('foo', 'w') { |f| f.write 'foo'}
+      File.open('foo', 'w') { |f| f.write 'foo' }
       Dir.chdir 'me' do
-        File.open('foobar', 'w') { |f| f.write 'foo'}
+        File.open('foobar', 'w') { |f| f.write 'foo' }
       end
     end
 
-    assert_equal ['/path/foo','/path/me'], Dir.glob('/path/*').sort
+    assert_equal ['/path/foo', '/path/me'], Dir.glob('/path/*').sort
+    assert_equal ['/path/me/foobar'], Dir.glob('/path/me/*').sort
+  end
+
+  def test_chdir_should_be_nestable_with_absolute_paths
+    FileUtils.mkdir_p '/path/me'
+    Dir.chdir '/path' do
+      File.open('foo', 'w') { |f| f.write 'foo' }
+      Dir.chdir '/path/me' do
+        File.open('foobar', 'w') { |f| f.write 'foo' }
+      end
+    end
+
+    assert_equal ['/path/foo', '/path/me'], Dir.glob('/path/*').sort
     assert_equal ['/path/me/foobar'], Dir.glob('/path/me/*').sort
   end
 
   def test_chdir_should_flop_over_and_die_if_the_dir_doesnt_exist
-    assert_raise(Errno::ENOENT) do
+    assert_raises(Errno::ENOENT) do
       Dir.chdir('/nope') do
         1
       end
@@ -1025,24 +1315,26 @@ class FakeFSTest < Test::Unit::TestCase
     FileUtils.mkdir_p '/path'
 
     Dir.chdir '/path' do
-      File.open('foo', 'w') { |f| f.write 'foo'}
-      File.open('foobar', 'w') { |f| f.write 'foo'}
+      File.open('foo', 'w') { |f| f.write 'foo' }
+      File.open('foobar', 'w') { |f| f.write 'foo' }
     end
 
     begin
       Dir.chdir('/path') do
-        raise Exception
+        fail Errno::ENOENT
       end
-    rescue Exception # hardcore
+    rescue Errno::ENOENT => e # hardcore
+      'Nothing to do'
     end
 
     Dir.chdir('/path') do
       begin
-        Dir.chdir('nope'){ }
-      rescue Errno::ENOENT
+        Dir.chdir('nope') {}
+      rescue Errno::ENOENT => e
+        'Nothing to do'
       end
 
-      assert_equal ['/path'], FileSystem.dir_levels
+      assert_equal ['/', '/path'], FakeFS::FileSystem.dir_levels
     end
 
     assert_equal(['/path/foo', '/path/foobar'], Dir.glob('/path/*').sort)
@@ -1054,7 +1346,7 @@ class FakeFSTest < Test::Unit::TestCase
     FileUtils.mkdir_p 'subdir'
     assert_equal ['subdir'], Dir.glob('*')
     Dir.chdir('subdir')
-    File.open('foo', 'w') { |f| f.write 'foo'}
+    File.open('foo', 'w') { |f| f.write 'foo' }
     assert_equal ['foo'], Dir.glob('*')
 
     assert_raises(Errno::ENOENT) do
@@ -1078,24 +1370,57 @@ class FakeFSTest < Test::Unit::TestCase
     assert_equal '/path/subdir', Dir.getwd
   end
 
+  def test_current_dir_reflected_by_expand_path_with_relative_paths
+    FileUtils.mkdir_p '/path'
+    Dir.chdir '/path'
+
+    assert_equal '/path', File.expand_path('.')
+    assert_equal '/path/foo', File.expand_path('foo')
+
+    FileUtils.mkdir_p 'subdir'
+    Dir.chdir 'subdir'
+
+    assert_equal '/path/subdir', File.expand_path('.')
+    assert_equal '/path/subdir/foo', File.expand_path('foo')
+  end
+
+  def test_expand_path_with_parent_dir
+    FakeFS.deactivate!
+    real = File.expand_path('../other.file', __FILE__)
+    FakeFS.activate!
+    fake = File.expand_path('../other.file', __FILE__)
+    assert_equal real, fake
+  end
+
+  def test_expand_path_works_with_absolute_paths
+    FakeFS.deactivate!
+    home = File.expand_path('~')
+    FakeFS.activate!
+    assert_equal "#{home}/dir/subdir", File.expand_path('subdir', '~/dir')
+    assert_equal '/somewhere/else', File.expand_path('else', '/somewhere')
+  end
+
   def test_file_open_defaults_to_read
-    File.open('foo','w') { |f| f.write 'bar' }
+    File.open('foo', 'w') { |f| f.write 'bar' }
     assert_equal 'bar', File.open('foo') { |f| f.read }
   end
 
   def test_flush_exists_on_file
-    r = File.open('foo','w') { |f| f.write 'bar';  f.flush }
+    r = File.open('foo', 'w') do |f|
+      f.write 'bar'
+      f.flush
+    end
     assert_equal 'foo', r.path
   end
 
   def test_mv_should_raise_error_on_missing_file
-    assert_raise(Errno::ENOENT) do
+    assert_raises(Errno::ENOENT) do
       FileUtils.mv 'blafgag', 'foo'
     end
-    exception = assert_raise(Errno::ENOENT) do
-      FileUtils.mv ['foo', 'bar'], 'destdir'
+    exception = assert_raises(Errno::ENOENT) do
+      FileUtils.mv %w(foo bar), 'destdir'
     end
-    assert_equal "No such file or directory - foo", exception.message
+    assert_equal 'No such file or directory - foo', exception.message
   end
 
   def test_mv_actually_works
@@ -1112,36 +1437,76 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_mv_works_with_options
-    File.open('foo', 'w') {|f| f.write 'bar'}
-    FileUtils.mv 'foo', 'baz', :force => true
+    File.open('foo', 'w') { |f| f.write 'bar' }
+    FileUtils.mv 'foo', 'baz', force: true
     assert_equal('bar', File.open('baz') { |f| f.read })
   end
 
   def test_mv_to_directory
-    File.open('foo', 'w') {|f| f.write 'bar'}
+    File.open('foo', 'w') { |f| f.write 'bar' }
     FileUtils.mkdir_p 'destdir'
     FileUtils.mv 'foo', 'destdir'
-    assert_equal('bar', File.open('destdir/foo') {|f| f.read })
+    assert_equal('bar', File.open('destdir/foo') { |f| f.read })
     assert File.directory?('destdir')
   end
 
   def test_mv_array
-    File.open('foo', 'w') {|f| f.write 'bar' }
-    File.open('baz', 'w') {|f| f.write 'binky' }
+    File.open('foo', 'w') { |f| f.write 'bar' }
+    File.open('baz', 'w') { |f| f.write 'binky' }
     FileUtils.mkdir_p 'destdir'
     FileUtils.mv %w(foo baz), 'destdir'
-    assert_equal('bar', File.open('destdir/foo') {|f| f.read })
-    assert_equal('binky', File.open('destdir/baz') {|f| f.read })
+    assert_equal('bar', File.open('destdir/foo') { |f| f.read })
+    assert_equal('binky', File.open('destdir/baz') { |f| f.read })
+  end
+
+  def test_mv_accepts_verbose_option
+    FileUtils.touch 'foo'
+    assert_equal "mv foo bar\n", capture_stderr { FileUtils.mv 'foo', 'bar', verbose: true }
+  end
+
+  def test_mv_accepts_noop_option
+    FileUtils.touch 'foo'
+    FileUtils.mv 'foo', 'bar', noop: true
+    assert File.exist?('foo'), 'does not remove src'
+    refute File.exist?('bar'), 'does not create target'
+  end
+
+  def test_mv_raises_when_moving_file_onto_directory
+    FileUtils.mkdir_p 'dir/stuff'
+    FileUtils.touch 'stuff'
+    assert_raises Errno::EEXIST do
+      FileUtils.mv 'stuff', 'dir'
+    end
+  end
+
+  def test_mv_raises_when_moving_to_non_existent_directory
+    FileUtils.touch 'stuff'
+    assert_raises Errno::ENOENT do
+      FileUtils.mv 'stuff', '/this/path/is/not/here'
+    end
+  end
+
+  def test_mv_ignores_failures_when_using_force
+    FileUtils.mkdir_p 'dir/stuff'
+    FileUtils.touch %w(stuff other)
+    FileUtils.mv %w(stuff other), 'dir', force: true
+    assert File.exist?('stuff'), 'failed move remains where it was'
+    assert File.exist?('dir/other'), 'successful one is moved'
+    refute File.exist?('other'), 'successful one is moved'
+
+    FileUtils.mv 'stuff', '/this/path/is/not/here', force: true
+    assert File.exist?('stuff'), 'failed move remains where it was'
+    refute File.exist?('/this/path/is/not/here'), 'nothing is created for a failed move'
   end
 
   def test_cp_actually_works
-    File.open('foo', 'w') {|f| f.write 'bar' }
+    File.open('foo', 'w') { |f| f.write 'bar' }
     FileUtils.cp('foo', 'baz')
     assert_equal 'bar', File.read('baz')
   end
 
   def test_cp_file_into_dir
-    File.open('foo', 'w') {|f| f.write 'bar' }
+    File.open('foo', 'w') { |f| f.write 'bar' }
     FileUtils.mkdir_p 'baz'
 
     FileUtils.cp('foo', 'baz')
@@ -1161,22 +1526,22 @@ class FakeFSTest < Test::Unit::TestCase
   def test_cp_fails_on_array_of_files_into_non_directory
     File.open('foo', 'w') { |f| f.write 'footext' }
 
-    exception = assert_raise(Errno::ENOTDIR) do
+    exception = assert_raises(Errno::ENOTDIR) do
       FileUtils.cp(%w(foo), 'baz')
     end
-    assert_equal "Not a directory - baz", exception.to_s
+    assert_equal 'Not a directory - baz', exception.to_s
   end
 
   def test_cp_overwrites_dest_file
-    File.open('foo', 'w') {|f| f.write 'FOO' }
-    File.open('bar', 'w') {|f| f.write 'BAR' }
+    File.open('foo', 'w') { |f| f.write 'FOO' }
+    File.open('bar', 'w') { |f| f.write 'BAR' }
 
     FileUtils.cp('foo', 'bar')
     assert_equal 'FOO', File.read('bar')
   end
 
   def test_cp_fails_on_no_source
-    assert_raise Errno::ENOENT do
+    assert_raises Errno::ENOENT do
       FileUtils.cp('foo', 'baz')
     end
   end
@@ -1184,11 +1549,17 @@ class FakeFSTest < Test::Unit::TestCase
   def test_cp_fails_on_directory_copy
     FileUtils.mkdir_p 'baz'
 
-    assert_raise Errno::EISDIR do
+    assert_raises Errno::EISDIR do
       FileUtils.cp('baz', 'bar')
     end
   end
 
+  def test_copy_file_works
+    File.open('foo', 'w') { |f| f.write 'bar' }
+    FileUtils.copy_file('foo', 'baz', :ignore_param_1, :ignore_param_2)
+    assert_equal 'bar', File.read('baz')
+  end
+
   def test_cp_r_doesnt_tangle_files_together
     File.open('foo', 'w') { |f| f.write 'bar' }
     FileUtils.cp_r('foo', 'baz')
@@ -1199,14 +1570,14 @@ class FakeFSTest < Test::Unit::TestCase
   def test_cp_r_should_raise_error_on_missing_file
     # Yes, this error sucks, but it conforms to the original Ruby
     # method.
-    assert_raise(RuntimeError) do
+    assert_raises(RuntimeError) do
       FileUtils.cp_r 'blafgag', 'foo'
     end
   end
 
   def test_cp_r_handles_copying_directories
     FileUtils.mkdir_p 'subdir'
-    Dir.chdir('subdir'){ File.open('foo', 'w') { |f| f.write 'footext' } }
+    Dir.chdir('subdir') { File.open('foo', 'w') { |f| f.write 'footext' } }
 
     FileUtils.mkdir_p 'baz'
 
@@ -1268,64 +1639,105 @@ class FakeFSTest < Test::Unit::TestCase
 
     FileUtils.cp_r '/path/foo', '/path/bar'
 
-    assert File.exists?('/path/bar/baz')
+    assert File.exist?('/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'))
-    FileSystem.clone(here('foo'))
-    assert_equal 'bar', File.open(here('foo')) { |f| f.read }
-  ensure
-    RealFile.unlink(here('foo')) if RealFile.exists?(here('foo'))
+    act_on_real_fs do
+      File.open(real_file_sandbox('foo'), 'w') do |f|
+        f.write 'bar'
+      end
+
+      assert RealFile.file?(real_file_sandbox('foo'))
+      assert File.file?(real_file_sandbox('foo'))
+    end
+
+    assert RealFile.file?(real_file_sandbox('foo'))
+
+    refute File.exist?(real_file_sandbox('foo'))
+    FakeFS::FileSystem.clone(real_file_sandbox('foo'))
+    assert_equal 'bar', File.open(real_file_sandbox('foo')) { |f| f.read }
   end
 
   def test_clone_clones_directories
-    act_on_real_fs { RealFileUtils.mkdir_p(here('subdir')) }
+    act_on_real_fs { FileUtils.mkdir_p(real_file_sandbox('subdir')) }
 
-    FileSystem.clone(here('subdir'))
+    FakeFS::FileSystem.clone(real_file_sandbox('subdir'))
 
-    assert File.exists?(here('subdir')), 'subdir was cloned'
-    assert File.directory?(here('subdir')), 'subdir is a directory'
-  ensure
-    act_on_real_fs { RealFileUtils.rm_rf(here('subdir')) }
+    assert File.exist?(real_file_sandbox('subdir')), 'subdir was cloned'
+    assert File.directory?(real_file_sandbox('subdir')), 'subdir is a directory'
   end
 
   def test_clone_clones_dot_files_even_hard_to_find_ones
-    act_on_real_fs { RealFileUtils.mkdir_p(here('subdir/.bar/baz/.quux/foo')) }
+    act_on_real_fs { FileUtils.mkdir_p(real_file_sandbox('subdir/.bar/baz/.quux/foo')) }
 
-    assert !File.exists?(here('subdir'))
+    refute File.exist?(real_file_sandbox('subdir'))
 
-    FileSystem.clone(here('subdir'))
-    assert_equal ['.', '..', '.bar'], Dir.entries(here('subdir'))
-    assert_equal ['.', '..', 'foo'], Dir.entries(here('subdir/.bar/baz/.quux'))
-  ensure
-    act_on_real_fs { RealFileUtils.rm_rf(here('subdir')) }
+    FakeFS::FileSystem.clone(real_file_sandbox('subdir'))
+    assert_equal ['.', '..', '.bar'], Dir.entries(real_file_sandbox('subdir'))
+    assert_equal ['.', '..', 'foo'], Dir.entries(real_file_sandbox('subdir/.bar/baz/.quux'))
   end
 
   def test_dir_glob_on_clone_with_absolute_path
-    act_on_real_fs { RealFileUtils.mkdir_p(here('subdir/.bar/baz/.quux/foo')) }
+    act_on_real_fs { FileUtils.mkdir_p(real_file_sandbox('subdir/.bar/baz/.quux/foo')) }
     FileUtils.mkdir_p '/path'
     Dir.chdir('/path')
-    FileSystem.clone(here('subdir'), "/foo")
-    assert Dir.glob "/foo/*"
-  ensure
-    act_on_real_fs { RealFileUtils.rm_rf(here('subdir')) }
+    FakeFS::FileSystem.clone(real_file_sandbox('subdir'), '/foo')
+    assert Dir.glob '/foo/*'
   end
 
   def test_clone_with_target_specified
-    act_on_real_fs { RealFileUtils.mkdir_p(here('subdir/.bar/baz/.quux/foo')) }
+    act_on_real_fs do
+      assert FileUtils == RealFileUtils, 'using the real FileUtils in act_on_real_fs'
+      FileUtils.mkdir_p(real_file_sandbox('subdir/.bar/baz/.quux/foo'))
+    end
+
+    refute File.exist?(real_file_sandbox('subdir'))
+
+    FakeFS::FileSystem.clone(real_file_sandbox('subdir'), real_file_sandbox('subdir2'))
+    refute File.exist?(real_file_sandbox('subdir'))
+    assert_equal ['.', '..', '.bar'], Dir.entries(real_file_sandbox('subdir2'))
+    assert_equal ['.', '..', 'foo'], Dir.entries(real_file_sandbox('subdir2/.bar/baz/.quux'))
+  end
+
+  def test_clone_with_file_symlinks
+    original = real_file_sandbox('subdir/test-file')
+    symlink  = real_file_sandbox('subdir/test-file.txt')
+
+    act_on_real_fs do
+      FileUtils.mkdir_p(File.dirname(original))
+      File.open(original, 'w') { |f| f << 'stuff' }
+      FileUtils.ln_s original, symlink
+      assert File.symlink?(symlink), 'real symlink is in place'
+    end
 
-    assert !File.exists?(here('subdir'))
+    refute File.exist?(original), 'file does not already exist'
 
-    FileSystem.clone(here('subdir'), here('subdir2'))
-    assert !File.exists?(here('subdir'))
-    assert_equal ['.', '..', '.bar'], Dir.entries(here('subdir2'))
-    assert_equal ['.', '..', 'foo'], Dir.entries(here('subdir2/.bar/baz/.quux'))
-  ensure
-    act_on_real_fs { RealFileUtils.rm_rf(here('subdir')) }
+    FakeFS::FileSystem.clone(File.dirname(original))
+    assert File.symlink?(symlink), 'symlinks are cloned as symlinks'
+    assert_equal 'stuff', File.read(symlink)
+  end
+
+  def test_clone_with_dir_symlinks
+    original = real_file_sandbox('subdir/dir')
+    symlink  = real_file_sandbox('subdir/dir.link')
+    original_file = File.join(original, 'test-file')
+    symlink_file  = File.join(symlink, 'test-file')
+
+    act_on_real_fs do
+      FileUtils.mkdir_p(original)
+      File.open(original_file, 'w') { |f| f << 'stuff' }
+      FileUtils.ln_s original, symlink
+      assert File.symlink?(symlink), 'real symlink is in place'
+    end
+
+    refute File.exist?(original_file), 'file does not already exist'
+
+    FakeFS::FileSystem.clone(File.dirname(original))
+    assert File.symlink?(symlink), 'symlinks are cloned as symlinks'
+    assert_equal 'stuff', File.read(symlink_file)
   end
 
   def test_putting_a_dot_at_end_copies_the_contents
@@ -1338,30 +1750,30 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_file_can_read_from_symlinks
-    File.open('first', 'w') { |f| f.write '1'}
+    File.open('first', 'w') { |f| f.write '1' }
     FileUtils.ln_s 'first', 'one'
     assert_equal '1', File.open('one') { |f| f.read }
 
     FileUtils.mkdir_p 'subdir'
-    File.open('subdir/nother','w') { |f| f.write 'works' }
+    File.open('subdir/nother', 'w') { |f| f.write 'works' }
     FileUtils.ln_s 'subdir', 'new'
     assert_equal 'works', File.open('new/nother') { |f| f.read }
   end
 
   def test_can_symlink_through_file
-    FileUtils.touch("/foo")
+    FileUtils.touch('/foo')
 
-    File.symlink("/foo", "/bar")
+    File.symlink('/foo', '/bar')
 
-    assert File.symlink?("/bar")
+    assert File.symlink?('/bar')
   end
 
   def test_files_can_be_touched
     FileUtils.touch('touched_file')
-    assert File.exists?('touched_file')
-    list = ['newfile', 'another']
+    assert File.exist?('touched_file')
+    list = %w(newfile another)
     FileUtils.touch(list)
-    list.each { |fp| assert(File.exists?(fp)) }
+    list.each { |fp| assert(File.exist?(fp)) }
   end
 
   def test_touch_does_not_work_if_the_dir_path_cannot_be_found
@@ -1377,16 +1789,15 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_extname
-    assert File.extname("test.doc") == ".doc"
+    assert File.extname('test.doc') == '.doc'
   end
 
   # Directory tests
   def test_new_directory
     FileUtils.mkdir_p('/this/path/should/be/here')
 
-    assert_nothing_raised do
-      Dir.new('/this/path/should/be/here')
-    end
+    # nothing raised
+    Dir.new('/this/path/should/be/here')
   end
 
   def test_new_directory_does_not_work_if_dir_path_cannot_be_found
@@ -1401,12 +1812,12 @@ class FakeFSTest < Test::Unit::TestCase
     assert dir.close.nil?
 
     assert_raises(IOError) do
-      dir.each { |dir| dir }
+      dir.each { |d| d }
     end
   end
 
   def test_directory_each
-    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5' ]
+    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5']
 
     FileUtils.mkdir_p('/this/path/should/be/here')
 
@@ -1417,8 +1828,8 @@ class FakeFSTest < Test::Unit::TestCase
     dir = Dir.new('/this/path/should/be/here')
 
     yielded = []
-    dir.each do |dir|
-      yielded << dir
+    dir.each do |d|
+      yielded << d
     end
 
     assert yielded.size == test.size
@@ -1432,7 +1843,7 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_directory_pos
-    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5' ]
+    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5']
     FileUtils.mkdir_p('/this/path/should/be/here')
     test.each do |f|
       FileUtils.touch("/this/path/should/be/here/#{f}")
@@ -1454,7 +1865,7 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_directory_pos_assign
-    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5' ]
+    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5']
 
     FileUtils.mkdir_p('/this/path/should/be/here')
     test.each do |f|
@@ -1469,7 +1880,7 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_directory_read
-    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5' ]
+    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5']
 
     FileUtils.mkdir_p('/this/path/should/be/here')
     test.each do |f|
@@ -1489,7 +1900,7 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_directory_read_past_length
-    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5' ]
+    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5']
 
     FileUtils.mkdir_p('/this/path/should/be/here')
     test.each do |f|
@@ -1499,25 +1910,25 @@ class FakeFSTest < Test::Unit::TestCase
     dir = Dir.new('/this/path/should/be/here')
 
     d = dir.read
-    assert_not_nil d
+    refute_nil d
     d = dir.read
-    assert_not_nil d
+    refute_nil d
     d = dir.read
-    assert_not_nil d
+    refute_nil d
     d = dir.read
-    assert_not_nil d
+    refute_nil d
     d = dir.read
-    assert_not_nil d
+    refute_nil d
     d = dir.read
-    assert_not_nil d
+    refute_nil d
     d = dir.read
-    assert_not_nil d
+    refute_nil d
     d = dir.read
     assert_nil d
   end
 
   def test_directory_rewind
-    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5' ]
+    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5']
 
     FileUtils.mkdir_p('/this/path/should/be/here')
     test.each do |f|
@@ -1526,15 +1937,15 @@ class FakeFSTest < Test::Unit::TestCase
 
     dir = Dir.new('/this/path/should/be/here')
 
-    d = dir.read
-    d = dir.read
+    dir.read
+    dir.read
     assert dir.pos == 2
     dir.rewind
     assert dir.pos == 0
   end
 
   def test_directory_seek
-    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5' ]
+    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5']
 
     FileUtils.mkdir_p('/this/path/should/be/here')
     test.each do |f|
@@ -1551,11 +1962,11 @@ class FakeFSTest < Test::Unit::TestCase
   def test_directory_class_delete
     FileUtils.mkdir_p('/this/path/should/be/here')
     Dir.delete('/this/path/should/be/here')
-    assert File.exists?('/this/path/should/be/here') == false
+    assert File.exist?('/this/path/should/be/here') == false
   end
 
   def test_directory_class_delete_does_not_act_on_non_empty_directory
-    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5' ]
+    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5']
 
     FileUtils.mkdir_p('/this/path/should/be/here')
     test.each do |f|
@@ -1574,7 +1985,7 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_directory_entries
-    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5' ]
+    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5']
 
     FileUtils.mkdir_p('/this/path/should/be/here')
 
@@ -1588,7 +1999,7 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_directory_entries_works_with_trailing_slash
-    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5' ]
+    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5']
 
     FileUtils.mkdir_p('/this/path/should/be/here')
 
@@ -1608,7 +2019,7 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_directory_foreach
-    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5' ]
+    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5']
 
     FileUtils.mkdir_p('/this/path/should/be/here')
 
@@ -1625,39 +2036,59 @@ class FakeFSTest < Test::Unit::TestCase
     test.each { |t| assert yielded.include?(t) }
   end
 
+  def test_directory_foreach_relative_paths
+    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5']
+
+    FileUtils.mkdir_p('/this/path/should/be/here')
+
+    test.each do |f|
+      FileUtils.touch("/this/path/should/be/here/#{f}")
+    end
+
+    yielded = []
+    Dir.chdir '/this/path/should/be' do
+      Dir.foreach('here') do |dir|
+        yielded << dir
+      end
+    end
+
+    assert yielded.size == test.size, 'wrong number of files yielded'
+    test.each { |t| assert yielded.include?(t), "#{t} was not included in #{yielded.inspect}" }
+  end
+
   def test_directory_mkdir
     Dir.mkdir('/path')
-    assert File.exists?('/path')
+    assert File.exist?('/path')
   end
 
   def test_directory_mkdir_nested
-    Dir.mkdir("/tmp")
-    Dir.mkdir("/tmp/stream20120103-11847-xc8pb.lock")
-    assert File.exists?("/tmp/stream20120103-11847-xc8pb.lock")
+    Dir.mkdir('/tmp')
+    Dir.mkdir('/tmp/stream20120103-11847-xc8pb.lock')
+    assert File.exist?('/tmp/stream20120103-11847-xc8pb.lock')
   end
 
   def test_can_create_subdirectories_with_dir_mkdir
     Dir.mkdir 'foo'
     Dir.mkdir 'foo/bar'
-    assert Dir.exists?('foo/bar')
+    assert Dir.exist?('foo/bar')
   end
 
   def test_can_create_absolute_subdirectories_with_dir_mkdir
     Dir.mkdir '/foo'
     Dir.mkdir '/foo/bar'
-    assert Dir.exists?('/foo/bar')
+    assert Dir.exist?('/foo/bar')
   end
 
   def test_can_create_directories_starting_with_dot
     Dir.mkdir './path'
-    assert File.exists? './path'
+    assert File.exist? './path'
   end
 
   def test_directory_mkdir_relative
     FileUtils.mkdir_p('/new/root')
-    FileSystem.chdir('/new/root')
+    FakeFS::FileSystem.chdir('/new/root')
     Dir.mkdir('path')
-    assert File.exists?('/new/root/path')
+    assert File.exist?('/new/root/path')
   end
 
   def test_directory_mkdir_not_recursive
@@ -1667,15 +2098,15 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_mkdir_raises_error_if_already_created
-    Dir.mkdir "foo"
+    Dir.mkdir 'foo'
 
     assert_raises(Errno::EEXIST) do
-      Dir.mkdir "foo"
+      Dir.mkdir 'foo'
     end
   end
 
   def test_directory_open
-    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5' ]
+    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5']
 
     FileUtils.mkdir_p('/this/path/should/be/here')
 
@@ -1688,7 +2119,7 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_directory_open_block
-    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5' ]
+    test = ['.', '..', 'file_1', 'file_2', 'file_3', 'file_4', 'file_5']
 
     FileUtils.mkdir_p('/this/path/should/be/here')
 
@@ -1705,239 +2136,247 @@ class FakeFSTest < Test::Unit::TestCase
     test.each { |t| assert yielded.include?(t) }
   end
 
+  def test_directory_exists
+    assert Dir.exist?('/this/path/should/be/here') == false
+    assert Dir.exist?('/this/path/should/be/here') == false
+    FileUtils.mkdir_p('/this/path/should/be/here')
+    assert Dir.exist?('/this/path/should/be/here') == true
+    assert Dir.exist?('/this/path/should/be/here') == true
+  end
+
   def test_tmpdir
-    assert Dir.tmpdir == "/tmp"
+    assert Dir.tmpdir == '/tmp'
   end
 
   def test_rename_renames_a_file
-    FileUtils.touch("/foo")
-    File.rename("/foo", "/bar")
-    assert File.file?("/bar")
+    FileUtils.touch('/foo')
+    File.rename('/foo', '/bar')
+    assert File.file?('/bar')
   end
 
   def test_rename_returns
-    FileUtils.touch("/foo")
-    assert_equal 0, File.rename("/foo", "/bar")
+    FileUtils.touch('/foo')
+    assert_equal 0, File.rename('/foo', '/bar')
   end
 
   def test_rename_renames_two_files
-    FileUtils.touch("/foo")
-    FileUtils.touch("/bar")
-    File.rename("/foo", "/bar")
-    assert File.file?("/bar")
+    FileUtils.touch('/foo')
+    FileUtils.touch('/bar')
+    File.rename('/foo', '/bar')
+    assert File.file?('/bar')
   end
 
   def test_rename_renames_a_directories
-    Dir.mkdir("/foo")
-    File.rename("/foo", "/bar")
-    assert File.directory?("/bar")
+    Dir.mkdir('/foo')
+    File.rename('/foo', '/bar')
+    assert File.directory?('/bar')
   end
 
   def test_rename_renames_two_directories
-    Dir.mkdir("/foo")
-    Dir.mkdir("/bar")
-    File.rename("/foo", "/bar")
-    assert File.directory?("/bar")
+    Dir.mkdir('/foo')
+    Dir.mkdir('/bar')
+    File.rename('/foo', '/bar')
+    assert File.directory?('/bar')
   end
 
   def test_rename_file_to_directory_raises_error
-    FileUtils.touch("/foo")
-    Dir.mkdir("/bar")
+    FileUtils.touch('/foo')
+    Dir.mkdir('/bar')
     assert_raises(Errno::EISDIR) do
-      File.rename("/foo", "/bar")
+      File.rename('/foo', '/bar')
     end
   end
 
   def test_rename_directory_to_file_raises_error
-    Dir.mkdir("/foo")
-    FileUtils.touch("/bar")
+    Dir.mkdir('/foo')
+    FileUtils.touch('/bar')
     assert_raises(Errno::ENOTDIR) do
-      File.rename("/foo", "/bar")
+      File.rename('/foo', '/bar')
     end
   end
 
-
   def test_rename_with_missing_source_raises_error
     assert_raises(Errno::ENOENT) do
-      File.rename("/no_such_file", "/bar")
+      File.rename('/no_such_file', '/bar')
+    end
+  end
+
+  def test_rename_with_missing_dest_directory_raises_error
+    FileUtils.touch('/foo')
+    assert_raises(Errno::ENOENT) do
+      File.rename('/foo', '/bar/foo')
     end
   end
 
   def test_hard_link_creates_file
-    FileUtils.touch("/foo")
+    FileUtils.touch('/foo')
 
-    File.link("/foo", "/bar")
-    assert File.exists?("/bar")
+    File.link('/foo', '/bar')
+    assert File.exist?('/bar')
   end
 
   def test_hard_link_with_missing_file_raises_error
     assert_raises(Errno::ENOENT) do
-      File.link("/foo", "/bar")
+      File.link('/foo', '/bar')
     end
   end
 
   def test_hard_link_with_existing_destination_file
-    FileUtils.touch("/foo")
-    FileUtils.touch("/bar")
+    FileUtils.touch('/foo')
+    FileUtils.touch('/bar')
 
     assert_raises(Errno::EEXIST) do
-      File.link("/foo", "/bar")
+      File.link('/foo', '/bar')
     end
   end
 
   def test_hard_link_returns_0_when_successful
-    FileUtils.touch("/foo")
+    FileUtils.touch('/foo')
 
-    assert_equal 0, File.link("/foo", "/bar")
+    assert_equal 0, File.link('/foo', '/bar')
   end
 
   def test_hard_link_returns_duplicate_file
-    File.open("/foo", "w") { |x| x << "some content" }
+    File.open('/foo', 'w') { |x| x << 'some content' }
 
-    File.link("/foo", "/bar")
-    assert_equal "some content", File.read("/bar")
+    File.link('/foo', '/bar')
+    assert_equal 'some content', File.read('/bar')
   end
 
   def test_hard_link_with_directory_raises_error
-    Dir.mkdir "/foo"
+    Dir.mkdir '/foo'
 
     assert_raises(Errno::EPERM) do
-      File.link("/foo", "/bar")
+      File.link('/foo', '/bar')
     end
   end
 
   def test_file_stat_returns_file_stat_object
-    FileUtils.touch("/foo")
-    assert_equal File::Stat, File.stat("/foo").class
+    FileUtils.touch('/foo')
+    assert_equal File::Stat, File.stat('/foo').class
   end
 
   def test_can_delete_file_with_delete
-    FileUtils.touch("/foo")
+    FileUtils.touch('/foo')
 
-    File.delete("/foo")
+    File.delete('/foo')
 
-    assert !File.exists?("/foo")
+    refute File.exist?('/foo')
   end
 
   def test_can_delete_multiple_files_with_delete
-    FileUtils.touch("/foo")
-    FileUtils.touch("/bar")
+    FileUtils.touch('/foo')
+    FileUtils.touch('/bar')
 
-    File.delete("/foo", "/bar")
+    File.delete('/foo', '/bar')
 
-    assert !File.exists?("/foo")
-    assert !File.exists?("/bar")
+    refute File.exist?('/foo')
+    refute File.exist?('/bar')
   end
 
-  def test_delete_raises_argument_error_with_no_filename_given
-    assert_raises ArgumentError do
-      File.delete
-    end
+  def test_delete_returns_zero_when_no_filename_given
+    assert_equal 0, File.delete
   end
 
   def test_delete_returns_number_one_when_given_one_arg
-    FileUtils.touch("/foo")
+    FileUtils.touch('/foo')
 
-    assert_equal 1, File.delete("/foo")
+    assert_equal 1, File.delete('/foo')
   end
 
   def test_delete_returns_number_two_when_given_two_args
-    FileUtils.touch("/foo")
-    FileUtils.touch("/bar")
+    FileUtils.touch('/foo')
+    FileUtils.touch('/bar')
 
-    assert_equal 2, File.delete("/foo", "/bar")
+    assert_equal 2, File.delete('/foo', '/bar')
   end
 
   def test_delete_raises_error_when_first_file_does_not_exist
     assert_raises Errno::ENOENT do
-      File.delete("/foo")
+      File.delete('/foo')
     end
   end
 
-  def test_unlink_is_alias_for_delete
-    assert_equal File.method(:unlink), File.method(:delete)
-  end
-
   def test_unlink_removes_only_one_file_content
-    File.open("/foo", "w") { |f| f << "some_content" }
-    File.link("/foo", "/bar")
+    File.open('/foo', 'w') { |f| f << 'some_content' }
+    File.link('/foo', '/bar')
 
-    File.unlink("/bar")
-    assert_equal "some_content", File.read("/foo")
+    File.unlink('/bar')
+    assert_equal 'some_content', File.read('/foo')
   end
 
   def test_link_reports_correct_stat_info_after_unlinking
-    File.open("/foo", "w") { |f| f << "some_content" }
-    File.link("/foo", "/bar")
+    File.open('/foo', 'w') { |f| f << 'some_content' }
+    File.link('/foo', '/bar')
 
-    File.unlink("/bar")
-    assert_equal 1, File.stat("/foo").nlink
+    File.unlink('/bar')
+    assert_equal 1, File.stat('/foo').nlink
   end
 
   def test_delete_works_with_symlink
-    FileUtils.touch("/foo")
-    File.symlink("/foo", "/bar")
+    FileUtils.touch('/foo')
+    File.symlink('/foo', '/bar')
 
-    File.unlink("/bar")
+    File.unlink('/bar')
 
-    assert File.exists?("/foo")
-    assert !File.exists?("/bar")
+    assert File.exist?('/foo')
+    refute File.exist?('/bar')
   end
 
   def test_delete_works_with_symlink_source
-    FileUtils.touch("/foo")
-    File.symlink("/foo", "/bar")
+    FileUtils.touch('/foo')
+    File.symlink('/foo', '/bar')
 
-    File.unlink("/foo")
+    File.unlink('/foo')
 
-    assert !File.exists?("/foo")
+    refute File.exist?('/foo')
   end
 
   def test_file_seek_returns_0
-    File.open("/foo", "w") do |f|
+    File.open('/foo', 'w') do |f|
       f << "one\ntwo\nthree"
     end
 
-    file = File.open("/foo", "r")
+    file = File.open('/foo', 'r')
 
     assert_equal 0, file.seek(1)
   end
 
   def test_file_seek_seeks_to_location
-    File.open("/foo", "w") do |f|
-      f << "123"
+    File.open('/foo', 'w') do |f|
+      f << '123'
     end
 
-    file = File.open("/foo", "r")
+    file = File.open('/foo', 'r')
     file.seek(1)
-    assert_equal "23", file.read
+    assert_equal '23', file.read
   end
 
   def test_file_seek_seeks_to_correct_location
-    File.open("/foo", "w") do |f|
-      f << "123"
+    File.open('/foo', 'w') do |f|
+      f << '123'
     end
 
-    file = File.open("/foo", "r")
+    file = File.open('/foo', 'r')
     file.seek(2)
-    assert_equal "3", file.read
+    assert_equal '3', file.read
   end
 
   def test_file_seek_can_take_negative_offset
-    File.open("/foo", "w") do |f|
-      f << "123456789"
+    File.open('/foo', 'w') do |f|
+      f << '123456789'
     end
 
-    file = File.open("/foo", "r")
+    file = File.open('/foo', 'r')
 
     file.seek(-1, IO::SEEK_END)
-    assert_equal "9", file.read
+    assert_equal '9', file.read
 
     file.seek(-2, IO::SEEK_END)
-    assert_equal "89", file.read
+    assert_equal '89', file.read
 
     file.seek(-3, IO::SEEK_END)
-    assert_equal "789", file.read
+    assert_equal '789', file.read
   end
 
   def test_should_have_constants_inherited_from_descending_from_io
@@ -1947,11 +2386,11 @@ class FakeFSTest < Test::Unit::TestCase
   end
 
   def test_filetest_exists_return_correct_values
-    FileUtils.mkdir_p("/path/to/dir")
-    assert FileTest.exist?("/path/to/")
+    FileUtils.mkdir_p('/path/to/dir')
+    assert FileTest.exist?('/path/to/')
 
-    FileUtils.rmdir("/path/to/dir")
-    assert !FileTest.exist?("/path/to/dir")
+    FileUtils.rmdir('/path/to/dir')
+    refute FileTest.exist?('/path/to/dir')
   end
 
   def test_filetest_directory_returns_correct_values
@@ -1959,28 +2398,41 @@ class FakeFSTest < Test::Unit::TestCase
     assert FileTest.directory?('/path/to/somedir')
 
     FileUtils.rm_r '/path/to/somedir'
-    assert !FileTest.directory?('/path/to/somedir')
+    refute FileTest.directory?('/path/to/somedir')
   end
 
   def test_filetest_file_returns_correct_values
-    FileUtils.mkdir_p("/path/to")
+    FileUtils.mkdir_p('/path/to')
 
     path = '/path/to/file.txt'
-    File.open(path, 'w') { |f| f.write "Yatta!" }
+    File.open(path, 'w') { |f| f.write 'Yatta!' }
     assert FileTest.file?(path)
 
     FileUtils.rm path
-    assert !FileTest.file?(path)
+    refute FileTest.file?(path)
 
     FileUtils.mkdir_p '/path/to/somedir'
-    assert !FileTest.file?('/path/to/somedir')
+    refute FileTest.file?('/path/to/somedir')
   end
 
-  def test_pathname_exists_returns_correct_value
-    FileUtils.touch "foo"
-    assert Pathname.new("foo").exist?
+  def test_filetest_readable_returns_correct_values
+    refute FileTest.readable?('not-here.txt'), 'missing files are not readable'
 
-    assert !Pathname.new("bar").exist?
+    FileUtils.touch 'here.txt'
+    assert FileTest.readable?('here.txt'), 'existing files are readable'
+
+    FileUtils.mkdir 'dir'
+    assert FileTest.readable?('dir'), 'directories are readable'
+  end
+
+  def test_filetest_writable_returns_correct_values
+    refute FileTest.writable?('not-here.txt'), 'missing files are not writable'
+
+    FileUtils.touch 'here.txt'
+    assert FileTest.writable?('here.txt'), 'existing files are writable'
+
+    FileUtils.mkdir 'dir'
+    assert FileTest.writable?('dir'), 'directories are writable'
   end
 
   def test_dir_mktmpdir
@@ -1994,7 +2446,7 @@ class FakeFSTest < Test::Unit::TestCase
       tmpdir = t
       assert File.directory?(t)
     end
-    assert !File.directory?(tmpdir)
+    refute File.directory?(tmpdir)
   end
 
   def test_activating_returns_true
@@ -2008,73 +2460,73 @@ class FakeFSTest < Test::Unit::TestCase
 
   def test_split
     assert File.respond_to? :split
-    filename = "/this/is/what/we/expect.txt"
-    path,filename = File.split(filename)
-    assert_equal path, "/this/is/what/we"
-    assert_equal filename, "expect.txt"
+    filename = '/this/is/what/we/expect.txt'
+    path, filename = File.split(filename)
+    assert_equal path, '/this/is/what/we'
+    assert_equal filename, 'expect.txt'
   end
 
   #########################
   def test_file_default_mode
-    FileUtils.touch "foo"
-    assert_equal File.stat("foo").mode, (0100000 + 0666 - File.umask)
+    FileUtils.touch 'foo'
+    assert_equal File.stat('foo').mode, (0100000 + 0666 - File.umask)
   end
 
   def test_dir_default_mode
-    Dir.mkdir "bar"
-    assert_equal File.stat("bar").mode, (0100000 + 0777 - File.umask)
+    Dir.mkdir 'bar'
+    assert_equal File.stat('bar').mode, (0100000 + 0777 - File.umask)
   end
 
   def test_file_default_uid_and_gid
-    FileUtils.touch "foo"
-    assert_equal File.stat("foo").uid, Process.uid
-    assert_equal File.stat("foo").gid, Process.gid
+    FileUtils.touch 'foo'
+    assert_equal File.stat('foo').uid, Process.uid
+    assert_equal File.stat('foo').gid, Process.gid
   end
 
   def test_file_chmod_of_file
-    FileUtils.touch "foo"
-    File.chmod 0600, "foo"
-    assert_equal File.stat("foo").mode, 0100600
-    File.new("foo").chmod 0644
-    assert_equal File.stat("foo").mode, 0100644
+    FileUtils.touch 'foo'
+    File.chmod 0600, 'foo'
+    assert_equal File.stat('foo').mode, 0100600
+    File.new('foo').chmod 0644
+    assert_equal File.stat('foo').mode, 0100644
   end
 
   def test_file_chmod_of_dir
-    Dir.mkdir "bar"
-    File.chmod 0777, "bar"
-    assert_equal File.stat("bar").mode, 0100777
-    File.new("bar").chmod 01700
-    assert_equal File.stat("bar").mode, 0101700
+    Dir.mkdir 'bar'
+    File.chmod 0777, 'bar'
+    assert_equal File.stat('bar').mode, 0100777
+    File.new('bar').chmod 01700
+    assert_equal File.stat('bar').mode, 0101700
   end
 
   def test_file_chown_of_file
-    FileUtils.touch "foo"
-    File.chown 1337, 1338, "foo"
-    assert_equal File.stat("foo").uid, 1337
-    assert_equal File.stat("foo").gid, 1338
+    FileUtils.touch 'foo'
+    File.chown 1337, 1338, 'foo'
+    assert_equal File.stat('foo').uid, 1337
+    assert_equal File.stat('foo').gid, 1338
   end
 
   def test_file_chown_of_dir
-    Dir.mkdir "bar"
-    File.chown 1337, 1338, "bar"
-    assert_equal File.stat("bar").uid, 1337
-    assert_equal File.stat("bar").gid, 1338
+    Dir.mkdir 'bar'
+    File.chown 1337, 1338, 'bar'
+    assert_equal File.stat('bar').uid, 1337
+    assert_equal File.stat('bar').gid, 1338
   end
 
   def test_file_chown_of_file_nil_user_group
-    FileUtils.touch "foo"
-    File.chown 1337, 1338, "foo"
-    File.chown nil, nil, "foo"
-    assert_equal File.stat("foo").uid, 1337
-    assert_equal File.stat("foo").gid, 1338
+    FileUtils.touch 'foo'
+    File.chown 1337, 1338, 'foo'
+    File.chown nil, nil, 'foo'
+    assert_equal File.stat('foo').uid, 1337
+    assert_equal File.stat('foo').gid, 1338
   end
 
   def test_file_chown_of_file_negative_user_group
-    FileUtils.touch "foo"
-    File.chown 1337, 1338, "foo"
-    File.chown -1, -1, "foo"
-    assert_equal File.stat("foo").uid, 1337
-    assert_equal File.stat("foo").gid, 1338
+    FileUtils.touch 'foo'
+    File.chown 1337, 1338, 'foo'
+    File.chown(-1, -1, 'foo')
+    assert_equal File.stat('foo').uid, 1337
+    assert_equal File.stat('foo').gid, 1338
   end
 
   def test_file_instance_chown_nil_user_group
@@ -2094,64 +2546,117 @@ class FakeFSTest < Test::Unit::TestCase
     assert_equal File.stat('foo').uid, 1337
     assert_equal File.stat('foo').gid, 1338
     file = File.new('foo')
-    file.chown -1, -1
+    file.chown(-1, -1)
     file.close
     assert_equal File.stat('foo').uid, 1337
     assert_equal File.stat('foo').gid, 1338
   end
 
-
   def test_file_umask
     assert_equal File.umask, RealFile.umask
+    File.umask(0740)
+
+    assert_equal File.umask, RealFile.umask
+    assert_equal File.umask, 0740
   end
 
   def test_file_stat_comparable
     a_time = Time.new
 
-    same1 = File.new("s1", "w")
-    same2 = File.new("s2", "w")
-    different1 = File.new("d1", "w")
-    different2 = File.new("d2", "w")
+    same1 = File.new('s1', 'w')
+    same2 = File.new('s2', 'w')
+    different1 = File.new('d1', 'w')
+    different2 = File.new('d2', 'w')
 
-    FileSystem.find("s1").mtime = a_time
-    FileSystem.find("s2").mtime = a_time
+    FakeFS::FileSystem.find('s1').mtime = a_time
+    FakeFS::FileSystem.find('s2').mtime = a_time
 
-    FileSystem.find("d1").mtime = a_time
-    FileSystem.find("d2").mtime = a_time + 1
+    FakeFS::FileSystem.find('d1').mtime = a_time
+    FakeFS::FileSystem.find('d2').mtime = a_time + 1
 
     assert same1.mtime == same2.mtime
     assert different1.mtime != different2.mtime
 
     assert same1.stat == same2.stat
-    assert (same1.stat <=> same2.stat) == 0
+    assert((same1.stat <=> same2.stat) == 0)
 
     assert different1.stat != different2.stat
-    assert (different1.stat <=> different2.stat) == -1
+    assert((different1.stat <=> different2.stat) == -1)
   end
 
-  def here(fname)
-    RealFile.expand_path(File.join(RealFile.dirname(__FILE__), fname))
+  def test_file_binread_works
+    File.open('testfile', 'w') do |f|
+      f << "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
+    end
+
+    assert_equal File.binread('testfile'), "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
+    assert_equal File.binread('testfile', 20), "This is line one\nThi"
+    assert_equal File.binread('testfile', 20, 10), "ne one\nThis is line "
+  end
+
+  def test_file_utils_compare_file
+    file1 = 'file1.txt'
+    file2 = 'file2.txt'
+    file3 = 'file3.txt'
+    content = "This is my \n file\content\n"
+    File.open(file1, 'w') do |f|
+      f.write content
+    end
+    File.open(file3, 'w') do |f|
+      f.write "#{content} with additional content"
+    end
+
+    FileUtils.cp file1, file2
+
+    assert_equal FileUtils.compare_file(file1, file2), true
+    assert_equal FileUtils.compare_file(file1, file3), false
+    assert_raises Errno::ENOENT do
+      FileUtils.compare_file(file1, 'file4.txt')
+    end
+  end
+
+  def test_fnmatch
+    assert_equal File.fnmatch?('test', 'test'), true
+    assert_equal File.fnmatch('nope', 'blargh'), false
+    assert_equal File.fnmatch?('nope', 'blargh'), File.fnmatch('nope', 'blargh')
+  end
+
+  if RUBY_VERSION >= '1.9.1'
+    def test_absolute_path_with_absolute_path
+      assert_equal '/foo/bar', File.absolute_path('/foo/bar')
+    end
+
+    def test_absolute_path_with_absolute_path_with_dir_name
+      assert_equal '/foo/bar', File.absolute_path('/foo/bar', '/dir')
+    end
+
+    def test_absolute_path_with_relative_path
+      assert_equal "#{Dir.getwd}foo/bar", File.absolute_path('foo/bar')
+    end
+
+    def test_absolute_path_with_relative_path_with_dir_name
+      assert_equal '/dir/foo/bar', File.absolute_path('foo/bar', '/dir')
+    end
   end
 
-  if RUBY_VERSION >= "1.9.2"
+  if RUBY_VERSION >= '1.9.2'
     def test_file_size
-      File.open("foo", 'w') do |f|
+      File.open('foo', 'w') do |f|
         f << 'Yada Yada'
         assert_equal 9, f.size
       end
     end
 
     def test_fdatasync
-      File.open("foo", 'w') do |f|
+      File.open('foo', 'w') do |f|
         f << 'Yada Yada'
-        assert_nothing_raised do
-          f.fdatasync
-        end
+        # nothing raised
+        f.fdatasync
       end
     end
 
     def test_autoclose
-      File.open("foo", 'w') do |f|
+      File.open('foo', 'w') do |f|
         assert_equal true, f.autoclose?
         f.autoclose = false
         assert_equal false, f.autoclose?
@@ -2159,19 +2664,98 @@ class FakeFSTest < Test::Unit::TestCase
     end
 
     def test_to_path
-      File.new("foo", 'w') do |f|
-        assert_equal "foo", f.to_path
+      File.new('foo', 'w') do |f|
+        assert_equal 'foo', f.to_path
       end
     end
   end
 
-  if RUBY_VERSION >= "1.9.3"
+  if RUBY_VERSION >= '1.9.3'
     def test_advise
-      File.open("foo", 'w') do |f|
-        assert_nothing_raised do
-          f.advise(:normal, 0, 0)
-        end
+      File.open('foo', 'w') do |f|
+        # nothing raised
+        f.advise(:normal, 0, 0)
+      end
+    end
+
+    def test_file_read_respects_hashes
+      path = 'file.txt'
+      File.open(path, 'w') do |f|
+        f.write 'Yatta!'
+      end
+
+      assert_equal 'ASCII-8BIT', File.read(path, mode: 'rb').encoding.to_s
+    end
+
+    def test_file_read_respects_args_and_hashes
+      path = 'file.txt'
+      File.open(path, 'w') do |f|
+        f.write 'Yatta!'
+      end
+
+      result = File.read(path, 2, 1, mode: 'rb')
+      assert_equal 'at', result
+      assert_equal 'ASCII-8BIT', result.encoding.to_s
+    end
+
+    def test_file_write_can_write_a_file
+      File.write('testfile', '0123456789')
+      assert_equal File.read('testfile'), '0123456789'
+    end
+
+    def test_file_write_returns_the_length_written
+      assert_equal File.write('testfile', '0123456789'), 10
+    end
+
+    def test_file_write_truncates_file_if_offset_not_given
+      File.open('foo', 'w') do |f|
+        f << 'foo'
+      end
+
+      File.write('foo', 'bar')
+      assert_equal File.read('foo'), 'bar'
+    end
+
+    def test_file_write_writes_at_offset_and_does_not_truncate
+      File.open('foo', 'w') do |f|
+        f << 'foo'
       end
+
+      File.write('foo', 'bar', 3)
+      assert_equal File.read('foo'), 'foobar'
+    end
+
+    def test_can_read_binary_data_in_binary_mode
+      File.open('foo', 'wb') { |f| f << "\u0000\u0000\u0000\u0003\u0000\u0003\u0000\xA3\u0000\u0000\u0000y\u0000\u0000\u0000\u0000\u0000" }
+      assert_equal "\x00\x00\x00\x03\x00\x03\x00\xA3\x00\x00\x00y\x00\x00\x00\x00\x00".force_encoding('ASCII-8BIT'), File.open('foo', 'rb').read
+    end
+
+    def test_can_read_binary_data_in_non_binary_mode
+      File.open('foo_non_bin', 'wb') { |f| f << "\u0000\u0000\u0000\u0003\u0000\u0003\u0000\xA3\u0000\u0000\u0000y\u0000\u0000\u0000\u0000\u0000" }
+      assert_equal "\x00\x00\x00\x03\x00\x03\x00\xA3\x00\x00\x00y\x00\x00\x00\x00\x00".force_encoding('UTF-8'), File.open('foo_non_bin', 'r').read
+    end
+
+    def test_can_read_binary_data_using_binread
+      File.open('foo', 'wb') { |f| f << "\u0000\u0000\u0000\u0003\u0000\u0003\u0000\xA3\u0000\u0000\u0000y\u0000\u0000\u0000\u0000\u0000" }
+      assert_equal "\x00\x00\x00\x03\x00\x03\x00\xA3\x00\x00\x00y\x00\x00\x00\x00\x00".force_encoding('ASCII-8BIT'), File.binread('foo')
+    end
+  end
+
+  if RUBY_VERSION >= '2.2.0'
+    def test_raises_error_on_birthtime_if_file_does_not_exist
+      assert_raises Errno::ENOENT do
+        File.birthtime('file.txt')
+      end
+    end
+
+    def test_can_return_birthtime_on_existing_file
+      File.open('foo', 'w') { |f| f << 'some content' }
+      assert File.birthtime('foo').is_a?(Time)
+    end
+
+    def test_file_birthtime_is_equal_to_file_stat_birthtime
+      File.open('foo', 'w') { |f| f << 'some content' }
+      assert_equal File.stat('foo').birthtime, File.birthtime('foo')
     end
   end
 end
diff --git a/test/file/stat_test.rb b/test/file/stat_test.rb
index 932ef70..9631cff 100644
--- a/test/file/stat_test.rb
+++ b/test/file/stat_test.rb
@@ -1,6 +1,7 @@
-require "test_helper"
+require 'test_helper'
 
-class FileStatTest < Test::Unit::TestCase
+# File stat test class
+class FileStatTest < Minitest::Test
   include FakeFS
 
   def setup
@@ -23,59 +24,68 @@ class FileStatTest < Test::Unit::TestCase
     File.link(*args)
   end
 
-  def test_file_stat_init_with_non_existant_file
+  def test_file_stat_init_with_non_existent_file
     assert_raises(Errno::ENOENT) do
-      File::Stat.new("/foo")
+      File::Stat.new('/foo')
     end
   end
 
+  def test_file_should_be_true_when_file
+    touch('/foo')
+    assert File::Stat.new('/foo').file?
+  end
+
   def test_symlink_should_be_true_when_symlink
-    touch("/foo")
-    ln_s("/foo", "/bar")
+    touch('/foo')
+    ln_s('/foo', '/bar')
 
-    assert File::Stat.new("/bar").symlink?
+    assert File::Stat.new('/bar').symlink?
+    assert File::Stat.new('/bar').ftype == 'link'
   end
 
   def test_symlink_should_be_false_when_not_a_symlink
-    FileUtils.touch("/foo")
+    FileUtils.touch('/foo')
 
-    assert !File::Stat.new("/foo").symlink?
+    refute File::Stat.new('/foo').symlink?
+    assert File::Stat.new('/foo').ftype == 'file'
   end
 
   def test_should_return_false_for_directory_when_not_a_directory
-    FileUtils.touch("/foo")
+    FileUtils.touch('/foo')
 
-    assert !File::Stat.new("/foo").directory?
+    refute File::Stat.new('/foo').directory?
+    assert File::Stat.new('/foo').ftype == 'file'
   end
 
   def test_should_return_true_for_directory_when_a_directory
-    mkdir "/foo"
+    mkdir '/foo'
 
-    assert File::Stat.new("/foo").directory?
+    assert File::Stat.new('/foo').directory?
+    assert File::Stat.new('/foo').ftype == 'directory'
   end
 
   def test_writable_is_true
-    touch("/foo")
+    touch('/foo')
 
-    assert File::Stat.new("/foo").writable?
+    assert File::Stat.new('/foo').writable?
   end
 
   def test_readable_is_true
-    touch("/foo")
+    touch('/foo')
 
-    assert File::Stat.new("/foo").readable?
+    assert File::Stat.new('/foo').readable?
   end
 
   def test_one_file_has_hard_link
-    touch "testfile"
-    assert_equal 1, File.stat("testfile").nlink
+    touch 'testfile'
+    assert_equal 1, File.stat('testfile').nlink
   end
 
   def test_two_hard_links_show_nlinks_as_two
-    touch "testfile"
-    ln    "testfile", "testfile.bak"
+    touch 'testfile'
+    ln 'testfile', 'testfile.bak'
 
-    assert_equal 2, File.stat("testfile").nlink
+    assert_equal 2, File.stat('testfile').nlink
   end
 
   def test_file_size
@@ -85,25 +95,64 @@ class FileStatTest < Test::Unit::TestCase
 
   def test_file_zero?
     File.open('testfile', 'w') { |f| f << 'test' }
-    assert !File.stat('testfile').zero?, "testfile has size 4, not zero"
+    refute File.stat('testfile').zero?, 'testfile has size 4, not zero'
 
     FileUtils.touch('testfile2')
-    assert File.stat('testfile2').zero?, "testfile2 has size 0, but stat lied"
+    assert File.stat('testfile2').zero?, 'testfile2 has size 0, but stat lied'
   end
 
   def test_touch_modifies_mtime
-    FileUtils.touch("/foo")
-    mtime = File.mtime("/foo")
+    FileUtils.touch('/foo')
+    mtime = File.mtime('/foo')
 
-    FileUtils.touch("/foo")
-    assert File.mtime("/foo") > mtime
+    FileUtils.touch('/foo')
+    assert File.mtime('/foo') > mtime
   end
 
   def test_writing_to_file_modifies_mtime
-    FileUtils.touch("/foo")
-    mtime = File.mtime("/foo")
+    FileUtils.touch('/foo')
+    mtime = File.mtime('/foo')
 
     File.open('/foo', 'w') { |f| f << 'test' }
-    assert File.mtime("/foo") > mtime
+    assert File.mtime('/foo') > mtime
+  end
+
+  def test_responds_to_world_writable
+    FileUtils.touch('/foo')
+    assert File::Stat.new('/foo').world_writable? == 0777
+  end
+
+  def test_responds_to_sticky
+    FileUtils.touch('/foo')
+    refute File::Stat.new('/foo').sticky?
+  end
+
+  def test_responds_to_world_readable
+    FileUtils.touch('/foo')
+    assert File::Stat.new('/foo').world_readable? == 0777, "#{File::Stat.new('/foo').world_readable?}"
+  end
+
+  def test_responds_to_world_readable
+    FakeFS do
+      require 'tempfile'
+      FileUtils.mkdir_p('/tmp')
+      ::Tempfile.open('test', '/tmp')
+    end
+  end
+
+  def test_responds_to_realpath_only_on_1_9
+    if RUBY_VERSION > '1.9'
+      assert File.respond_to?(:realpath)
+    else
+      refute File.respond_to?(:realpath)
+    end
+  end
+
+  def test_responds_to_realdirpath_only_on_1_9_2_and_greater
+    if RUBY_VERSION >= '1.9.2'
+      assert File.respond_to?(:realdirpath)
+    else
+      refute File.respond_to?(:realdirpath)
+    end
   end
 end
diff --git a/test/kernel_test.rb b/test/kernel_test.rb
new file mode 100644
index 0000000..22269f8
--- /dev/null
+++ b/test/kernel_test.rb
@@ -0,0 +1,53 @@
+require 'test_helper'
+
+# Kernel test class
+class KernelTest < Minitest::Test
+  include FakeFS
+  def setup
+    FakeFS.deactivate!
+  end
+
+  def teardown
+    FakeFS.activate!
+  end
+
+  def test_can_exec_normally
+    out = open("|echo 'foo'")
+    assert_equal "foo\n", out.gets
+  end
+
+  def test_fake_kernel_can_create_subprocesses
+    FakeFS do
+      out = open("|echo 'foo'")
+      assert_equal "foo\n", out.gets
+    end
+  end
+
+  def test_fake_kernel_can_create_new_file
+    FakeFS do
+      FileUtils.mkdir_p '/path/to/'
+      open('/path/to/file', 'w') do |f|
+        f << 'test'
+      end
+      assert_kind_of FakeFile, FileSystem.fs['path']['to']['file']
+    end
+  end
+
+  def test_fake_kernel_can_do_stuff
+    FakeFS do
+      FileUtils.mkdir_p('/tmp')
+      File.open('/tmp/a', 'w+') { |f| f.puts 'test' }
+
+      begin
+        open('/tmp/a').read
+      rescue => e
+        raise e
+      end
+    end
+  end
+
+  def test_can_exec_normally2
+    out = open("|echo 'foo'")
+    assert_equal "foo\n", out.gets
+  end
+end
diff --git a/test/pathname_test.rb b/test/pathname_test.rb
new file mode 100644
index 0000000..62643f1
--- /dev/null
+++ b/test/pathname_test.rb
@@ -0,0 +1,75 @@
+require 'test_helper'
+
+# Fake Pathname test class
+class FakePathnameTest < Minitest::Test
+  include FakeFS
+
+  def setup
+    FakeFS.activate!
+    FileSystem.clear
+
+    @path = 'foo'
+    @pathname = Pathname.new(@path)
+  end
+
+  def teardown
+    FakeFS.deactivate!
+  end
+
+  def test_filetest_exists_returns_correct_value
+    refute @pathname.exist?
+
+    File.write(@path, '')
+
+    assert @pathname.exist?
+  end
+
+  def test_io_each_line_with_block_yields_lines
+    File.write(@path, "one\ntwo\nthree\n")
+
+    yielded = []
+    @pathname.each_line { |line| yielded << line }
+
+    assert_equal yielded, ["one\n", "two\n", "three\n"]
+  end
+
+  def test_io_each_line_without_block_returns_enumerator
+    File.write(@path, "one\ntwo\nthree\n")
+
+    assert @pathname.each_line.is_a?(Enumerator)
+    assert_equal %w(o t t), @pathname.each_line.map { |l| l[0] }
+    assert_equal ["one\ntwo\nth", "ree\n"], @pathname.each_line('th').to_a
+  end
+
+  def test_io_read_returns_file_contents
+    File.write(@path, "some\ncontent")
+
+    assert_equal "some\ncontent", @pathname.read
+    assert_equal "some\nc", @pathname.read(6)
+    assert_equal "e\nco", @pathname.read(4, 3)
+  end
+
+  def test_io_binread_returns_file_contents
+    File.write(@path, "some\ncontent")
+
+    assert_equal "some\ncontent", @pathname.binread
+    assert_equal "some\nc", @pathname.binread(6)
+    assert_equal "e\nco", @pathname.binread(4, 3)
+  end
+
+  def test_io_binread_reads_contents_as_binary
+    File.write(@path, "some\ncontent")
+
+    assert_equal 'ASCII-8BIT', @pathname.binread.encoding.name
+  end
+
+  def test_io_readlines_returns_array_of_lines
+    File.write(@path, "one\ntwo\nthree\n")
+
+    assert_equal ["one\n", "two\n", "three\n"], @pathname.readlines
+  end
+
+  def test_io_sysopen_is_unsupported
+    assert_raises(NotImplementedError) { @pathname.sysopen }
+  end
+end
diff --git a/test/safe_test.rb b/test/safe_test.rb
index c4c1224..651b518 100644
--- a/test/safe_test.rb
+++ b/test/safe_test.rb
@@ -1,6 +1,7 @@
-require "test_helper"
+require 'test_helper'
 
-class FakeFSSafeTest < Test::Unit::TestCase
+# FakeFS safe test class
+class FakeFSSafeTest < Minitest::Test
   def setup
     FakeFS.deactivate!
   end
@@ -12,7 +13,7 @@ class FakeFSSafeTest < Test::Unit::TestCase
   def test_FakeFS_activated_is_accurate
     2.times do
       FakeFS.deactivate!
-      assert !FakeFS.activated?
+      refute FakeFS.activated?
       FakeFS.activate!
       assert FakeFS.activated?
     end
@@ -22,20 +23,20 @@ class FakeFSSafeTest < Test::Unit::TestCase
     path = 'file.txt'
 
     FakeFS do
-      File.open(path, 'w') { |f| f.write "Yatta!" }
-      assert File.exists?(path)
+      File.open(path, 'w') { |f| f.write 'Yatta!' }
+      assert File.exist?(path)
     end
 
-    assert ! File.exists?(path)
+    refute File.exist?(path)
   end
 
   def test_FakeFS_method_returns_value_of_yield
     result = FakeFS do
-      File.open('myfile.txt', 'w') { |f| f.write "Yatta!" }
+      File.open('myfile.txt', 'w') { |f| f.write 'Yatta!' }
       File.read('myfile.txt')
     end
 
-    assert_equal result, "Yatta!"
+    assert_equal result, 'Yatta!'
   end
 
   def test_FakeFS_method_does_not_deactivate_FakeFS_if_already_activated
@@ -54,29 +55,30 @@ class FakeFSSafeTest < Test::Unit::TestCase
       assert FakeFS.activated?
     end
 
-    assert !FakeFS.activated?
+    refute FakeFS.activated?
   end
 
   def test_FakeFS_method_can_be_nested_with_FakeFS_without
     FakeFS do
       assert FakeFS.activated?
       FakeFS.without do
-        assert !FakeFS.activated?
+        refute FakeFS.activated?
       end
       assert FakeFS.activated?
     end
 
-    assert !FakeFS.activated?
+    refute FakeFS.activated?
   end
 
   def test_FakeFS_method_deactivates_FakeFS_when_block_raises_exception
     begin
       FakeFS do
-        raise 'boom!'
+        fail 'boom!'
       end
     rescue
+      'Nothing to do'
     end
 
-    assert !FakeFS.activated?
+    refute FakeFS.activated?
   end
 end
diff --git a/test/test_helper.rb b/test/test_helper.rb
index b6596fa..31d17d5 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -1,15 +1,33 @@
 $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
 require 'fakefs/safe'
-require 'test/unit'
+require 'minitest/autorun'
+require 'minitest/rg'
 
-begin
-  require 'redgreen'
-rescue LoadError
+def act_on_real_fs(&block)
+  FakeFS.without(&block)
 end
 
-def act_on_real_fs
-  raise ArgumentError unless block_given?
-  FakeFS.deactivate!
+def capture_stderr
+  real_stderr, $stderr = $stderr, StringIO.new
+
+  # force FileUtils to use our stderr
+  RealFileUtils.instance_variable_set('@fileutils_output', $stderr)
+
   yield
-  FakeFS.activate!
+
+  return $stderr.string
+ensure
+  $stderr = real_stderr
+
+  # restore FileUtils stderr
+  RealFileUtils.instance_variable_set('@fileutils_output', $stderr)
+end
+
+def real_file_sandbox(path = nil)
+  base_path = real_file_sandbox_path
+  path ? File.join(base_path, path) : base_path
+end
+
+def real_file_sandbox_path
+  File.expand_path(File.join(File.dirname(__FILE__), '..', 'test_sandbox'))
 end
diff --git a/test/verify.rb b/test/verify.rb
index 4df051d..83cebd8 100644
--- a/test/verify.rb
+++ b/test/verify.rb
@@ -4,9 +4,10 @@
 #
 #   $ RUBYLIB=test ruby test/verify.rb | grep "not implemented"
 
-require "test_helper"
+require 'test_helper'
 
-class FakeFSVerifierTest < Test::Unit::TestCase
+# FakeFs verifier test class
+class FakeFSVerifierTest < Minitest::Test
   class_mapping = {
     RealFile       => FakeFS::File,
     RealFile::Stat => FakeFS::File::Stat,
@@ -17,14 +18,16 @@ class FakeFSVerifierTest < Test::Unit::TestCase
 
   class_mapping.each do |real_class, fake_class|
     real_class.methods.each do |method|
-      define_method "test #{method} class method" do
-        assert fake_class.respond_to?(method), "#{fake_class}.#{method} not implemented"
+      define_method "test_#{method}_class_method" do
+        assert fake_class.respond_to?(method),
+               "#{fake_class}.#{method} not implemented"
       end
     end
 
     real_class.instance_methods.each do |method|
-      define_method("test #{method} instance method") do
-        assert fake_class.instance_methods.include?(method), "#{fake_class}##{method} not implemented"
+      define_method("test_#{method}_instance_method") do
+        assert fake_class.instance_methods.include?(method),
+               "#{fake_class}##{method} not implemented"
       end
     end
   end

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-fakefs.git



More information about the Pkg-ruby-extras-commits mailing list