diff --git a/lib/memfs.rb b/lib/memfs.rb index 46c6da0..66d53b7 100644 --- a/lib/memfs.rb +++ b/lib/memfs.rb @@ -35,6 +35,78 @@ def self.windows? /mswin|bccwin|mingw/ =~ RUBY_PLATFORM end + # Returns the platform-specific root path (e.g., '/' on Unix, 'D:/' on Windows) + def self.platform_root + @platform_root || default_platform_root + end + + # Allows setting a custom platform root (mainly for testing) + def self.platform_root=(value) + @platform_root = value + end + + # Resets platform_root to the default value + def self.reset_platform_root! + @platform_root = nil + end + + # Returns the default platform root based on the current OS + def self.default_platform_root + if windows? + # Normalize drive letter to uppercase + OriginalFile.expand_path('/').sub(/\A([a-z]):/) { "#{::Regexp.last_match(1).upcase}:" } + else + '/' + end + end + + # Check if a path is the root path (handles both '/' and 'D:/') + def self.root_path?(path) + return false if path.nil? + + normalized = normalize_path(path) + normalized == platform_root || normalized == '/' + end + + # Normalize path for consistent handling + # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength + # rubocop:disable Metrics/PerceivedComplexity + def self.normalize_path(path) + return path unless path.is_a?(String) + + # Reject UNC paths + fail ArgumentError, "UNC paths are not supported: #{path}" if path.start_with?('\\\\', '//') + + # Convert backslashes to forward slashes + path = path.tr('\\', '/') + + return path unless windows? + + # Normalize drive letter to uppercase + path = path.sub(/\A([a-z]):/) { "#{::Regexp.last_match(1).upcase}:" } + + # Handle drive-relative paths like 'D:foo' or 'D:.' (no slash after colon) + # and bare drive letters like 'D:' (current directory on drive D) + # Convert to absolute paths since our fake fs doesn't support per-drive working directories + if path.match?(/\A[A-Z]:\z/) # Bare drive like 'D:' + path = "#{path}/" + elsif path.match?(%r{\A[A-Z]:[^/]}) # Drive-relative like 'D:foo' or 'D:.' + path = path.sub(/\A([A-Z]):/, '\1:/') + end + + # Convert bare '/' to platform root on Windows + if path == '/' + platform_root + elsif path.start_with?('/') && !path.match?(%r{\A[A-Z]:/}) + # Convert '/foo' to 'D:/foo' on Windows + "#{platform_root}#{path[1..]}" + else + path + end + end + # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength + # rubocop:enable Metrics/PerceivedComplexity + require 'memfs/file_system' require 'memfs/dir' require 'memfs/file' diff --git a/lib/memfs/dir.rb b/lib/memfs/dir.rb index ed72ed7..1ae84da 100644 --- a/lib/memfs/dir.rb +++ b/lib/memfs/dir.rb @@ -32,7 +32,7 @@ def self.chroot(path) fail Errno::EPERM, path unless Process.uid.zero? dir = fs.find_directory!(path) - dir.name = '/' + dir.name = MemFs.platform_root fs.root = dir 0 end @@ -63,25 +63,35 @@ def self.getwd class << self; alias pwd getwd; end # rubocop:disable Lint/UnderscorePrefixedVariableName, Lint/UnusedMethodArgument + # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength + # rubocop:disable Metrics/PerceivedComplexity def self.glob(patterns, _flags = 0, flags: _flags, base: nil, sort: true, &block) # rubocop:enable Lint/UnderscorePrefixedVariableName, Lint/UnusedMethodArgument - patterns = [*patterns].map(&:to_s) + original_patterns = [*patterns].map(&:to_s) + # Normalize patterns for platform (e.g., '/test' -> 'D:/test' on Windows) + normalized_patterns = original_patterns.map { |p| MemFs.normalize_path(p) } list = fs.paths.select do |path| - patterns.any? do |pattern| + normalized_patterns.any? do |pattern| File.fnmatch?(pattern, path, flags | GLOB_FLAGS) end end # Special case for /* and / # A scenario where /* is not the only pattern and / should be returned is - # considered an edge-case. - list.delete('/') if patterns.first == '/*' + # considered an edge-case (platform-aware root handling). + root_pattern = MemFs.windows? ? "#{MemFs.platform_root}*" : '/*' + if ['/*', root_pattern].include?(original_patterns.first) + list.delete(MemFs.platform_root) + list.delete('/') # Also handle Unix-style if passed + end return list unless block_given? list.each(&block) nil end + # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength + # rubocop:enable Metrics/PerceivedComplexity def self.home(*args) original_dir_class.home(*args) @@ -108,17 +118,20 @@ def self.rmdir(path) end def self.tmpdir - '/tmp' + File.join(MemFs.platform_root, 'tmp') end # rubocop:disable Metrics/MethodLength def self.mktmpdir(prefix_suffix = nil, tmpdir = nil, **options) - tmpdir ||= self.tmpdir + tmpdir = MemFs.normalize_path(tmpdir || self.tmpdir) path = MemFs::OriginalDir::Tmpname.create( prefix_suffix || 'd', tmpdir, **options) { |p, _, _, _d| mkdir(p, 0o700) } + # Normalize the returned path for consistent handling across platforms + path = MemFs.normalize_path(path) + return path unless block_given? begin diff --git a/lib/memfs/fake/directory.rb b/lib/memfs/fake/directory.rb index 8861b3e..797e397 100644 --- a/lib/memfs/fake/directory.rb +++ b/lib/memfs/fake/directory.rb @@ -20,8 +20,20 @@ def entry_names entries.keys end + # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity def find(path) + path = MemFs.normalize_path(path) + + # Strip root prefix if present (platform_root first, then directory name for root dirs) + if path.start_with?(MemFs.platform_root) + path = path[MemFs.platform_root.length..] + elsif root_directory? && path.start_with?(name) + path = path[name.length..] + end + path = path.gsub(%r{(\A/+|/+\z)}, '') + return self if path.empty? + parts = path.split('/', 2) if entry_names.include?(path) @@ -30,6 +42,7 @@ def find(path) entries[parts.first].find(parts.last) end end + # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity def initialize(*args) super @@ -42,7 +55,7 @@ def parent=(parent) end def path - name == '/' ? '/' : super + root_directory? ? name : super end def paths @@ -63,6 +76,12 @@ def remove_entry(entry) def type 'directory' end + + private + + def root_directory? + parent.nil? || MemFs.root_path?(name) + end end end end diff --git a/lib/memfs/fake/entry.rb b/lib/memfs/fake/entry.rb index e3ce6e8..d39c7e3 100644 --- a/lib/memfs/fake/entry.rb +++ b/lib/memfs/fake/entry.rb @@ -61,18 +61,25 @@ def find(_path) fail Errno::ENOTDIR, path end + # rubocop:disable Metrics/AbcSize, Metrics/MethodLength def initialize(path = nil) time = Time.now - self.atime = time self.birthtime = time self.ctime = time self.gid = Process.egid self.mode = 0o666 - MemFs::File.umask self.mtime = time - self.name = MemFs::File.basename(path || '') + # Preserve full path for root directories (e.g., 'D:/' on Windows) + # since File.basename('D:/') returns '/' which breaks path matching + self.name = if path && MemFs.root_path?(path) + MemFs.normalize_path(path) + else + MemFs::File.basename(path || '') + end self.uid = Process.euid end + # rubocop:enable Metrics/AbcSize, Metrics/MethodLength def ino @ino ||= rand(1000) diff --git a/lib/memfs/file_system.rb b/lib/memfs/file_system.rb index 6c7b5cc..74bb98a 100644 --- a/lib/memfs/file_system.rb +++ b/lib/memfs/file_system.rb @@ -29,9 +29,10 @@ def chdir(path) end def clear! - self.root = Fake::Directory.new('/') - mkdir '/tmp' - chdir '/' + MemFs.reset_platform_root! + self.root = Fake::Directory.new(MemFs.platform_root) + mkdir File.join(MemFs.platform_root, 'tmp') + chdir MemFs.platform_root end def chmod(mode_int, file_name) @@ -53,7 +54,9 @@ def entries(path) end def find(path) - if path == '/' + path = MemFs.normalize_path(path) + + if MemFs.root_path?(path) root elsif dirname(path) == '.' working_directory.find(path) diff --git a/spec/fileutils_spec.rb b/spec/fileutils_spec.rb index 0ff4ca7..96ed0d3 100644 --- a/spec/fileutils_spec.rb +++ b/spec/fileutils_spec.rb @@ -17,7 +17,7 @@ describe '.cd' do it 'changes the current working directory' do described_class.cd '/test' - expect(described_class.pwd).to eq('/test') + expect(described_class.pwd).to eq(expected_path('/test')) end if MemFs.ruby_version_gte?('2.6') @@ -42,7 +42,7 @@ context 'when called with a block' do it 'changes current working directory for the block execution' do described_class.cd '/test' do - expect(described_class.pwd).to eq('/test') + expect(described_class.pwd).to eq(expected_path('/test')) end end @@ -59,7 +59,7 @@ it 'changes directory to the last target of the link chain' do described_class.cd('/test-link') - expect(described_class.pwd).to eq('/test') + expect(described_class.pwd).to eq(expected_path('/test')) end it "raises an error if the last target of the link chain doesn't exist" do @@ -765,7 +765,7 @@ describe '.pwd' do it 'returns the name of the current directory' do described_class.cd '/test' - expect(described_class.pwd).to eq('/test') + expect(described_class.pwd).to eq(expected_path('/test')) end end diff --git a/spec/memfs/dir_spec.rb b/spec/memfs/dir_spec.rb index c74464f..4d6d439 100644 --- a/spec/memfs/dir_spec.rb +++ b/spec/memfs/dir_spec.rb @@ -13,13 +13,13 @@ module MemFs describe '[]' do context 'when a string is given' do it 'acts like calling glob' do - expect(described_class['/*']).to eq %w[/tmp /test] + expect(described_class['/*']).to eq [expected_path('/tmp'), expected_path('/test')] end end context 'when a list of strings is given' do it 'acts like calling glob' do - expect(described_class['/tm*', '/te*']).to eq %w[/tmp /test] + expect(described_class['/tm*', '/te*']).to eq [expected_path('/tmp'), expected_path('/test')] end end end @@ -27,7 +27,7 @@ module MemFs describe '.chdir' do it 'changes the current working directory' do described_class.chdir '/test' - expect(described_class.getwd).to eq('/test') + expect(described_class.getwd).to eq(expected_path('/test')) end it 'returns zero' do @@ -41,7 +41,7 @@ module MemFs context 'when a block is given' do it 'changes current working directory for the block' do described_class.chdir '/test' do - expect(described_class.pwd).to eq('/test') + expect(described_class.pwd).to eq(expected_path('/test')) end end @@ -250,7 +250,8 @@ module MemFs shared_examples 'returning matching filenames' do |pattern, filenames| it "with #{pattern}" do - expect(described_class.glob(pattern)).to eq filenames + expected = filenames.map { |f| expected_path(f) } + expect(described_class.glob(pattern)).to eq expected end end @@ -274,14 +275,14 @@ module MemFs context 'when a flag is given' do it 'uses it to compare filenames' do expect(described_class.glob('/TEST*', File::FNM_CASEFOLD)).to eq \ - %w[/test0 /test1 /test2] + [expected_path('/test0'), expected_path('/test1'), expected_path('/test2')] end end context 'when a block is given' do it 'calls the block with every matching filenames' do expect { |blk| described_class.glob('/test*', &blk) }.to \ - yield_successive_args('/test0', '/test1', '/test2') + yield_successive_args(expected_path('/test0'), expected_path('/test1'), expected_path('/test2')) end it 'returns nil' do @@ -291,20 +292,22 @@ module MemFs context 'when pattern is an array of patterns' do it 'returns the list of files matching any pattern' do - expect(described_class.glob(['/*0', '/*1'])).to eq %w[/test0 /test1] + expect(described_class.glob(['/*0', '/*1'])).to eq [expected_path('/test0'), expected_path('/test1')] end end end describe '.home' do it 'returns the home directory of the current user' do - expect(described_class.home).to eq ENV['HOME'] + # Dir.home uses forward slashes; ENV['HOME'] may have backslashes on Windows + expect(described_class.home).to eq ENV['HOME'].tr('\\', '/') end context 'when a username is given' do it 'returns the home directory of the given user' do - home_dir = described_class.home(ENV['USER']) - expect(home_dir).to eq ENV['HOME'] + username = ENV['USER'] || ENV['USERNAME'] + home_dir = described_class.home(username) + expect(home_dir).to eq ENV['HOME'].tr('\\', '/') end end end @@ -419,7 +422,7 @@ module MemFs describe '.tmpdir' do it 'returns /tmp' do - expect(described_class.tmpdir).to eq '/tmp' + expect(described_class.tmpdir).to eq expected_path('/tmp') end end @@ -437,19 +440,19 @@ module MemFs context 'when no block is given' do it 'creates a temporary directory and returns its path' do path = described_class.mktmpdir - expect(path).to start_with('/tmp/d') + expect(path).to start_with(expected_path('/tmp/d')) expect(described_class.exist?(path)).to be true end it 'accepts a prefix' do path = described_class.mktmpdir('myprefix') - expect(path).to start_with('/tmp/myprefix') + expect(path).to start_with(expected_path('/tmp/myprefix')) expect(described_class.exist?(path)).to be true end it 'accepts a prefix and suffix as an array' do path = described_class.mktmpdir(['prefix_', '_suffix']) - expect(path).to start_with('/tmp/prefix_') + expect(path).to start_with(expected_path('/tmp/prefix_')) expect(path).to end_with('_suffix') expect(described_class.exist?(path)).to be true end @@ -457,7 +460,7 @@ module MemFs it 'accepts a custom tmpdir' do described_class.mkdir('/custom_tmp') path = described_class.mktmpdir(nil, '/custom_tmp') - expect(path).to start_with('/custom_tmp/d') + expect(path).to start_with(expected_path('/custom_tmp/d')) expect(described_class.exist?(path)).to be true end end @@ -467,7 +470,7 @@ module MemFs yielded_path = nil described_class.mktmpdir do |path| yielded_path = path - expect(path).to start_with('/tmp/d') + expect(path).to start_with(expected_path('/tmp/d')) expect(described_class.exist?(path)).to be true end expect(described_class.exist?(yielded_path)).to be false @@ -489,7 +492,7 @@ module MemFs yielded_path = nil described_class.mktmpdir('test_') do |path| yielded_path = path - expect(path).to start_with('/tmp/test_') + expect(path).to start_with(expected_path('/tmp/test_')) expect(described_class.exist?(path)).to be true end expect(described_class.exist?(yielded_path)).to be false @@ -544,7 +547,7 @@ module MemFs describe '#path' do it "returns the path parameter passed to dir's constructor" do - expect(subject.path).to eq '/test' + expect(subject.path).to eq expected_path('/test') end end @@ -655,7 +658,7 @@ module MemFs describe '#to_path' do it "returns the path parameter passed to dir's constructor" do - expect(subject.to_path).to eq '/test' + expect(subject.to_path).to eq expected_path('/test') end end end diff --git a/spec/memfs/fake/directory_spec.rb b/spec/memfs/fake/directory_spec.rb index 83bdb49..8ea3123 100644 --- a/spec/memfs/fake/directory_spec.rb +++ b/spec/memfs/fake/directory_spec.rb @@ -91,16 +91,16 @@ module Fake end describe '#path' do - let(:root) { described_class.new('/') } + let(:root) { described_class.new(root_path) } it 'returns the directory path' do directory.parent = root - expect(directory.path).to eq('/test') + expect(directory.path).to eq(expected_path('/test')) end context 'when the directory is /' do it 'returns /' do - expect(root.path).to eq('/') + expect(root.path).to eq(root_path) end end end diff --git a/spec/memfs/fake/entry_spec.rb b/spec/memfs/fake/entry_spec.rb index 3eeb48b..1bc63ad 100644 --- a/spec/memfs/fake/entry_spec.rb +++ b/spec/memfs/fake/entry_spec.rb @@ -113,7 +113,7 @@ module Fake describe '#dereferenced_path' do it 'returns the entry path' do - expect(entry.dereferenced_path).to eq('/parent/test') + expect(entry.dereferenced_path).to eq(expected_path('/parent/test')) end end @@ -143,13 +143,13 @@ module Fake describe '#path' do it 'returns the complete path of the entry' do - expect(entry.path).to eq('/parent/test') + expect(entry.path).to eq(expected_path('/parent/test')) end end describe 'paths' do it 'returns an array containing the entry path' do - expect(entry.paths).to eq ['/parent/test'] + expect(entry.paths).to eq [expected_path('/parent/test')] end end diff --git a/spec/memfs/fake/symlink_spec.rb b/spec/memfs/fake/symlink_spec.rb index 146dc32..d6bdac6 100644 --- a/spec/memfs/fake/symlink_spec.rb +++ b/spec/memfs/fake/symlink_spec.rb @@ -54,7 +54,7 @@ module Fake it 'returns its target path' do _fs.touch('/test-file') symlink = described_class.new('/test-link', '/test-file') - expect(symlink.dereferenced_path).to eq('/test-file') + expect(symlink.dereferenced_path).to eq(expected_path('/test-file')) end end diff --git a/spec/memfs/file/stat_spec.rb b/spec/memfs/file/stat_spec.rb index bb50c4a..604c9a3 100644 --- a/spec/memfs/file/stat_spec.rb +++ b/spec/memfs/file/stat_spec.rb @@ -453,7 +453,7 @@ module MemFs context 'when the effective user group does not own of the file' do it 'returns false' do - _fs.chown(0, 0, '/test-file') + _fs.chown(9999, 9999, '/test-file') expect(file_stat.grpowned?).to be false end end @@ -482,7 +482,7 @@ module MemFs context 'when the effective user does not own of the file' do it 'returns false' do - _fs.chown(0, 0, '/test-file') + _fs.chown(9999, 9999, '/test-file') expect(file_stat.owned?).to be false end end diff --git a/spec/memfs/file_spec.rb b/spec/memfs/file_spec.rb index dcb81ae..371cc43 100644 --- a/spec/memfs/file_spec.rb +++ b/spec/memfs/file_spec.rb @@ -40,20 +40,20 @@ module MemFs it 'converts a pathname to an absolute pathname' do path = described_class.absolute_path('./test-file') - expect(path).to eq '/test-dir/test-file' + expect(path).to eq expected_path('/test-dir/test-file') end context 'when +dir_string+ is given' do it 'uses it as the starting point' do path = described_class.absolute_path('./test-file', '/no-dir') - expect(path).to eq '/no-dir/test-file' + expect(path).to eq expected_path('/no-dir/test-file') end end context "when the given pathname starts with a '~'" do it 'does not expanded' do path = described_class.absolute_path('~/test-file') - expect(path).to eq '/test-dir/~/test-file' + expect(path).to eq expected_path('/test-dir/~/test-file') end end end @@ -490,20 +490,20 @@ module MemFs _fs.chdir '/' expanded_path = described_class.expand_path('test-file') - expect(expanded_path).to eq '/test-file' + expect(expanded_path).to eq expected_path('/test-file') end it 'references path from the current working directory' do _fs.chdir '/test-dir' expanded_path = described_class.expand_path('test-file') - expect(expanded_path).to eq '/test-dir/test-file' + expect(expanded_path).to eq expected_path('/test-dir/test-file') end context 'when +dir_string+ is provided' do it 'uses +dir_string+ as the stating point' do expanded_path = described_class.expand_path('test-file', '/test') - expect(expanded_path).to eq '/test/test-file' + expect(expanded_path).to eq expected_path('/test/test-file') end end end @@ -662,7 +662,7 @@ module MemFs context 'and the effective user group does not own of the file' do it 'returns false' do - described_class.chown 0, 0, '/test-file' + described_class.chown 9999, 9999, '/test-file' grpowned = File.grpowned?('/test-file') expect(grpowned).to be false @@ -1013,7 +1013,7 @@ module MemFs context 'and the effective user does not own of the file' do it 'returns false' do - described_class.chown 0, 0, '/test-file' + described_class.chown 9999, 9999, '/test-file' owned = File.owned?('/test-file') expect(owned).to be false @@ -1258,7 +1258,7 @@ module MemFs context 'when the path does not contain any symlink or useless dots' do it 'returns the path itself' do path = described_class.realdirpath('/test-file') - expect(path).to eq '/test-file' + expect(path).to eq expected_path('/test-file') end end @@ -1266,14 +1266,14 @@ module MemFs context 'and the symlink is a middle part' do it 'returns the path with the symlink dereferrenced' do path = described_class.realdirpath('/test-dir/sub-dir-link/test-file') - expect(path).to eq '/test-dir/sub-dir/test-file' + expect(path).to eq expected_path('/test-dir/sub-dir/test-file') end end context 'and the symlink is the last part' do it 'returns the path with the symlink dereferrenced' do path = described_class.realdirpath('/test-dir/sub-dir-link') - expect(path).to eq '/test-dir/sub-dir' + expect(path).to eq expected_path('/test-dir/sub-dir') end end end @@ -1281,7 +1281,7 @@ module MemFs context 'when the path contains useless dots' do it 'returns the path with the useless dots interpolated' do path = described_class.realdirpath('/test-dir/../test-dir/./sub-dir/test-file') - expect(path).to eq '/test-dir/sub-dir/test-file' + expect(path).to eq expected_path('/test-dir/sub-dir/test-file') end end @@ -1290,14 +1290,14 @@ module MemFs it 'uses the current working directory has base directory' do _fs.chdir '/test-dir' path = described_class.realdirpath('../test-dir/./sub-dir/test-file') - expect(path).to eq '/test-dir/sub-dir/test-file' + expect(path).to eq expected_path('/test-dir/sub-dir/test-file') end end context 'and +dir_string+ is provided' do it 'uses the given directory has base directory' do path = described_class.realdirpath('../test-dir/./sub-dir/test-file', '/test-dir') - expect(path).to eq '/test-dir/sub-dir/test-file' + expect(path).to eq expected_path('/test-dir/sub-dir/test-file') end end end @@ -1310,7 +1310,7 @@ module MemFs it 'uses the name of the target in the resulting path' do path = described_class.realdirpath('/test-dir/sub-dir/test-link') - expect(path).to eq '/test-dir/sub-dir/test' + expect(path).to eq expected_path('/test-dir/sub-dir/test') end end end @@ -1318,7 +1318,7 @@ module MemFs context 'when the last part of the given path does not exist' do it 'uses its name in the resulting path' do path = described_class.realdirpath('/test-dir/sub-dir/test') - expect(path).to eq '/test-dir/sub-dir/test' + expect(path).to eq expected_path('/test-dir/sub-dir/test') end end @@ -1341,7 +1341,7 @@ module MemFs context 'when the path does not contain any symlink or useless dots' do it 'returns the path itself' do path = described_class.realpath('/test-file') - expect(path).to eq '/test-file' + expect(path).to eq expected_path('/test-file') end end @@ -1349,14 +1349,14 @@ module MemFs context 'and the symlink is a middle part' do it 'returns the path with the symlink dereferrenced' do path = described_class.realpath('/test-dir/sub-dir-link/test-file') - expect(path).to eq '/test-dir/sub-dir/test-file' + expect(path).to eq expected_path('/test-dir/sub-dir/test-file') end end context 'and the symlink is the last part' do it 'returns the path with the symlink dereferrenced' do path = described_class.realpath('/test-dir/sub-dir-link') - expect(path).to eq '/test-dir/sub-dir' + expect(path).to eq expected_path('/test-dir/sub-dir') end end end @@ -1364,7 +1364,7 @@ module MemFs context 'when the path contains useless dots' do it 'returns the path with the useless dots interpolated' do path = described_class.realpath('/test-dir/../test-dir/./sub-dir/test-file') - expect(path).to eq '/test-dir/sub-dir/test-file' + expect(path).to eq expected_path('/test-dir/sub-dir/test-file') end end @@ -1374,14 +1374,14 @@ module MemFs _fs.chdir '/test-dir' path = described_class.realpath('../test-dir/./sub-dir/test-file') - expect(path).to eq '/test-dir/sub-dir/test-file' + expect(path).to eq expected_path('/test-dir/sub-dir/test-file') end end context 'and +dir_string+ is provided' do it 'uses the given directory has base directory' do path = described_class.realpath('../test-dir/./sub-dir/test-file', '/test-dir') - expect(path).to eq '/test-dir/sub-dir/test-file' + expect(path).to eq expected_path('/test-dir/sub-dir/test-file') end end end diff --git a/spec/memfs/file_system_spec.rb b/spec/memfs/file_system_spec.rb index 1b9191f..86979bf 100644 --- a/spec/memfs/file_system_spec.rb +++ b/spec/memfs/file_system_spec.rb @@ -11,7 +11,7 @@ module MemFs describe '#chdir' do it 'changes the current working directory' do subject.chdir '/test-dir' - expect(subject.getwd).to eq('/test-dir') + expect(subject.getwd).to eq(expected_path('/test-dir')) end it 'raises an error if directory does not exist' do @@ -29,7 +29,7 @@ module MemFs subject.chdir '/test-dir' do location = subject.getwd end - expect(location).to eq('/test-dir') + expect(location).to eq(expected_path('/test-dir')) end it 'gets back to previous directory once the block is finished' do @@ -44,7 +44,7 @@ module MemFs it 'sets current directory as the last link chain target' do subject.symlink('/test-dir', '/test-link') subject.chdir('/test-link') - expect(subject.getwd).to eq('/test-dir') + expect(subject.getwd).to eq(expected_path('/test-dir')) end end end @@ -140,7 +140,7 @@ module MemFs it 'sets the current directory to /' do subject.clear! - expect(subject.getwd).to eq('/') + expect(subject.getwd).to eq(root_path) end end @@ -256,7 +256,7 @@ module MemFs describe '#getwd' do it 'returns the current working directory' do subject.chdir '/test-dir' - expect(subject.getwd).to eq('/test-dir') + expect(subject.getwd).to eq(expected_path('/test-dir')) end end @@ -329,8 +329,8 @@ module MemFs end it 'returns the list of all the existing paths' do - expect(subject.paths).to eq \ - %w[/ /tmp /test-dir /test-dir/subdir /test-dir/subdir/file1 /test-dir/subdir/file2] + expected = %w[/ /tmp /test-dir /test-dir/subdir /test-dir/subdir/file1 /test-dir/subdir/file2] + expect(subject.paths).to eq(expected.map { |p| expected_path(p) }) end end diff --git a/spec/memfs_spec.rb b/spec/memfs_spec.rb index c8b96a8..f24c111 100644 --- a/spec/memfs_spec.rb +++ b/spec/memfs_spec.rb @@ -95,7 +95,7 @@ it 'creates the file in the in-memory filesystem' do file = Tempfile.create('memfs') expect(file).to be_a(File) - expect(file.path).to start_with('/tmp/memfs') + expect(file.path).to start_with(expected_path('/tmp/memfs')) expect(_fs.find(file.path)).not_to be_nil file.close end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 20e0d0a..6181977 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -10,6 +10,17 @@ def _fs MemFs::FileSystem.instance end +# Returns the platform-appropriate root path +def root_path + MemFs.platform_root +end + +# Converts Unix-style path to platform path for expectations +# expected_path('/test-file') => '/test-file' on Unix, 'D:/test-file' on Windows +def expected_path(unix_path) + MemFs.normalize_path(unix_path) +end + RSpec.configure do |config| config.expect_with :rspec do |expectations| expectations.include_chain_clauses_in_custom_matcher_descriptions = true