1require 'test/unit'
2require 'tmpdir'
3require_relative 'envutil'
4
5class TestDir_M17N < Test::Unit::TestCase
6  def with_tmpdir
7    Dir.mktmpdir {|dir|
8      Dir.chdir(dir) {
9        yield dir
10      }
11    }
12  end
13
14  def create_and_check_raw_file_name(code, encoding)
15    with_tmpdir { |dir|
16      create_file_program = %Q[
17        filename = #{code}.chr('UTF-8').force_encoding("#{encoding}")
18        File.open(filename, "w") {}
19        opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
20        ents = Dir.entries(".", opts)
21        exit ents.include?(filename)
22      ]
23      assert_ruby_status(["-E#{encoding}"], create_file_program, nil, :chdir=>dir)
24
25      test_file_program = %Q[
26        filename = #{code}.chr('UTF-8').force_encoding("ASCII-8BIT")
27        opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
28        ents = Dir.entries(".", opts)
29        expected_filename = #{code}.chr('UTF-8').encode(Encoding.find("filesystem")) rescue expected_filename = "?"
30        expected_filename = expected_filename.force_encoding("ASCII-8BIT")
31        result = ents.include?(filename) || (/mswin|mingw/ =~ RUBY_PLATFORM && ents.include?(expected_filename))
32        if !result && /mswin|mingw/ =~ RUBY_PLATFORM
33          exit Dir.entries(".", {:encoding => Encoding.find("filesystem")}).include?(expected_filename)
34        end
35        exit result
36      ]
37      assert_ruby_status(%w[-EASCII-8BIT], test_file_program, nil, :chdir=>dir)
38    }
39  end
40
41  ## UTF-8 default_external, no default_internal
42
43  def test_filename_extutf8
44    with_tmpdir {|d|
45      assert_ruby_status(%w[-EUTF-8], <<-'EOS', nil, :chdir=>d)
46        filename = "\u3042"
47        File.open(filename, "w") {}
48        opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
49        ents = Dir.entries(".", opts)
50        exit ents.include?(filename)
51      EOS
52    }
53  end
54
55  def test_filename_extutf8_invalid
56    with_tmpdir {|d|
57      assert_ruby_status(%w[-EASCII-8BIT], <<-'EOS', nil, :chdir=>d)
58        filename = "\xff".force_encoding("ASCII-8BIT") # invalid byte sequence as UTF-8
59        File.open(filename, "w") {}
60        opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
61        ents = Dir.entries(".", opts)
62        exit ents.include?(filename) || (/darwin/ =~ RUBY_PLATFORM && ents.include?("%FF"))
63      EOS
64      assert_ruby_status(%w[-EUTF-8], <<-'EOS', nil, :chdir=>d)
65        filename = "\xff".force_encoding("UTF-8") # invalid byte sequence as UTF-8
66        File.open(filename, "w") {}
67        opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
68        ents = Dir.entries(".", opts)
69        exit ents.include?(filename) || (/darwin/ =~ RUBY_PLATFORM && ents.include?("%FF"))
70      EOS
71    }
72  end unless /mswin|mingw/ =~ RUBY_PLATFORM
73
74  def test_filename_as_bytes_extutf8
75    with_tmpdir {|d|
76      assert_ruby_status(%w[-EUTF-8], <<-'EOS', nil, :chdir=>d)
77        filename = "\xc2\xa1".force_encoding("utf-8")
78        File.open(filename, "w") {}
79        opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
80        ents = Dir.entries(".", opts)
81        exit ents.include?(filename)
82      EOS
83      assert_ruby_status(%w[-EUTF-8], <<-'EOS', nil, :chdir=>d)
84        if /mswin|mingw/ =~ RUBY_PLATFORM
85          filename = "\x8f\xa2\xc2".force_encoding("euc-jp")
86        else
87          filename = "\xc2\xa1".force_encoding("euc-jp")
88        end
89        begin
90          open(filename) {}
91          exit true
92        rescue Errno::ENOENT
93          exit false
94        end
95      EOS
96      # no meaning test on windows
97      unless /mswin|mingw/ =~ RUBY_PLATFORM
98        assert_ruby_status(%w[-EUTF-8], <<-'EOS', nil, :chdir=>d)
99          filename1 = "\xc2\xa1".force_encoding("utf-8")
100          filename2 = "\xc2\xa1".force_encoding("euc-jp")
101          filename3 = filename1.encode("euc-jp")
102          filename4 = filename2.encode("utf-8")
103          s1 = File.stat(filename1) rescue nil
104          s2 = File.stat(filename2) rescue nil
105          s3 = File.stat(filename3) rescue nil
106          s4 = File.stat(filename4) rescue nil
107          exit((s1 && s2 && !s3 && !s4) ? true : false)
108        EOS
109      end
110    }
111  end
112
113  ## UTF-8 default_external, EUC-JP default_internal
114
115  def test_filename_extutf8_inteucjp_representable
116    with_tmpdir {|d|
117      assert_ruby_status(%w[-EUTF-8], <<-'EOS', nil, :chdir=>d)
118        filename = "\u3042"
119        File.open(filename, "w") {}
120        opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
121        ents = Dir.entries(".", opts)
122        exit ents.include?(filename)
123      EOS
124      assert_ruby_status(%w[-EUTF-8:EUC-JP], <<-'EOS', nil, :chdir=>d)
125        filename = "\xA4\xA2".force_encoding("euc-jp")
126        opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
127        ents = Dir.entries(".", opts)
128        exit ents.include?(filename)
129      EOS
130      assert_ruby_status(%w[-EUTF-8:EUC-JP], <<-'EOS', nil, :chdir=>d)
131        filename = "\xA4\xA2".force_encoding("euc-jp")
132        begin
133          open(filename) {}
134          exit true
135        rescue Errno::ENOENT
136          exit false
137        end
138      EOS
139    }
140  end
141
142  def test_filename_extutf8_inteucjp_unrepresentable
143    with_tmpdir {|d|
144      assert_ruby_status(%w[-EUTF-8], <<-'EOS', nil, :chdir=>d)
145        filename1 = "\u2661" # WHITE HEART SUIT which is not representable in EUC-JP
146        filename2 = "\u3042" # HIRAGANA LETTER A which is representable in EUC-JP
147        File.open(filename1, "w") {}
148        File.open(filename2, "w") {}
149        opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
150        ents = Dir.entries(".", opts)
151        exit ents.include?(filename1) && ents.include?(filename2)
152      EOS
153      assert_ruby_status(%w[-EUTF-8:EUC-JP], <<-'EOS', nil, :chdir=>d)
154        filename1 = "\u2661" # WHITE HEART SUIT which is not representable in EUC-JP
155        filename2 = "\xA4\xA2".force_encoding("euc-jp") # HIRAGANA LETTER A in EUC-JP
156        opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
157        ents = Dir.entries(".", opts)
158        exit ents.include?(filename1) && ents.include?(filename2)
159      EOS
160      assert_ruby_status(%w[-EUTF-8:EUC-JP], <<-'EOS', nil, :chdir=>d)
161        filename1 = "\u2661" # WHITE HEART SUIT which is not representable in EUC-JP
162        filename2 = "\u3042" # HIRAGANA LETTER A which is representable in EUC-JP
163        filename3 = "\xA4\xA2".force_encoding("euc-jp") # HIRAGANA LETTER A in EUC-JP
164        s1 = File.stat(filename1) rescue nil
165        s2 = File.stat(filename2) rescue nil
166        s3 = File.stat(filename3) rescue nil
167        exit((s1 && s2 && s3) ? true : false)
168      EOS
169    }
170  end
171
172  ## others
173
174  def test_filename_bytes_euc_jp
175    with_tmpdir {|d|
176      assert_ruby_status(%w[-EEUC-JP], <<-'EOS', nil, :chdir=>d)
177        filename = "\xA4\xA2".force_encoding("euc-jp")
178        File.open(filename, "w") {}
179        opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
180        ents = Dir.entries(".", opts)
181        ents.each {|e| e.force_encoding("ASCII-8BIT") }
182        exit ents.include?(filename.force_encoding("ASCII-8BIT")) ||
183               (/darwin/ =~ RUBY_PLATFORM && ents.include?("%A4%A2".force_encoding("ASCII-8BIT")))
184      EOS
185    }
186  end
187
188  def test_filename_euc_jp
189    with_tmpdir {|d|
190      assert_ruby_status(%w[-EEUC-JP], <<-'EOS', nil, :chdir=>d)
191        filename = "\xA4\xA2".force_encoding("euc-jp")
192        File.open(filename, "w") {}
193        opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
194        ents = Dir.entries(".", opts)
195        exit ents.include?(filename) || (/darwin/ =~ RUBY_PLATFORM && ents.include?("%A4%A2".force_encoding("euc-jp")))
196      EOS
197      assert_ruby_status(%w[-EASCII-8BIT], <<-'EOS', nil, :chdir=>d)
198        filename = "\xA4\xA2".force_encoding('ASCII-8BIT')
199        win_expected_filename = filename.encode(Encoding.find("filesystem"), "euc-jp") rescue "?"
200        opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
201        ents = Dir.entries(".", opts)
202        result = ents.include?(filename) ||
203               (/darwin/ =~ RUBY_PLATFORM && ents.include?("%A4%A2".force_encoding("ASCII-8BIT"))) ||
204               (/mswin|mingw/ =~ RUBY_PLATFORM && ents.include?(win_expected_filename.force_encoding("ASCII-8BIT")))
205        if !result && /mswin|mingw/ =~ RUBY_PLATFORM
206          exit Dir.entries(".", {:encoding => Encoding.find("filesystem")}).include?(win_expected_filename)
207        end
208        exit result
209      EOS
210    }
211  end
212
213  def test_filename_utf8_raw_jp_name
214    create_and_check_raw_file_name(0x3042, "UTF-8")
215  end
216
217  def test_filename_utf8_raw_windows_1251_name
218    create_and_check_raw_file_name(0x0424, "UTF-8")
219  end
220
221  def test_filename_utf8_raw_windows_1252_name
222    create_and_check_raw_file_name(0x00c6, "UTF-8")
223  end
224
225  def test_filename_ext_euc_jp_and_int_utf_8
226    with_tmpdir {|d|
227      assert_ruby_status(%w[-EEUC-JP], <<-'EOS', nil, :chdir=>d)
228        filename = "\xA4\xA2".force_encoding("euc-jp")
229        File.open(filename, "w") {}
230        opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
231        ents = Dir.entries(".", opts)
232        exit ents.include?(filename) || (/darwin/ =~ RUBY_PLATFORM && ents.include?("%A4%A2".force_encoding("euc-jp")))
233      EOS
234      assert_ruby_status(%w[-EEUC-JP:UTF-8], <<-'EOS', nil, :chdir=>d)
235        filename = "\u3042"
236        opts = {:encoding => Encoding.default_external} if /mswin|mingw/ =~ RUBY_PLATFORM
237        ents = Dir.entries(".", opts)
238        exit ents.include?(filename) || (/darwin/ =~ RUBY_PLATFORM && ents.include?("%A4%A2"))
239      EOS
240    }
241  end
242
243  def test_error_nonascii
244    bug6071 = '[ruby-dev:45279]'
245    paths = ["\u{3042}".encode("sjis"), "\u{ff}".encode("iso-8859-1")]
246    encs = with_tmpdir {
247      paths.map {|path|
248        Dir.open(path) rescue $!.message.encoding
249      }
250    }
251    assert_equal(paths.map(&:encoding), encs, bug6071)
252  end
253
254  def test_inspect_nonascii
255    bug6072 = '[ruby-dev:45280]'
256    paths = ["\u{3042}".encode("sjis"), "\u{ff}".encode("iso-8859-1")]
257    encs = with_tmpdir {
258      paths.map {|path|
259        Dir.mkdir(path)
260        Dir.open(path) {|d| d.inspect.encoding}
261      }
262    }
263    assert_equal(paths.map(&:encoding), encs, bug6072)
264  end
265
266  def test_glob_incompatible
267    d = "\u{3042}\u{3044}".encode("utf-16le")
268    assert_raise(Encoding::CompatibilityError) {Dir.glob(d)}
269    m = Class.new {define_method(:to_path) {d}}
270    assert_raise(Encoding::CompatibilityError) {Dir.glob(m.new)}
271  end
272end
273