summaryrefslogtreecommitdiff
path: root/spec/ruby/core/file/join_spec.rb
blob: 0feedbae93c499df01203a6c6a1699c4a666476a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
require_relative '../../spec_helper'

describe "File.join" do
  # see [ruby-core:46804] for the 4 following rules
  it "changes only boundaries separators" do
    File.join("file/\\/usr/", "/bin").should == "file/\\/usr/bin"
    File.join("file://usr", "bin").should == "file://usr/bin"
  end

  it "respects the given separator if only one part has a boundary separator" do
    File.join("usr/", "bin").should == "usr/bin"
    File.join("usr", "/bin").should == "usr/bin"
    File.join("usr//", "bin").should == "usr//bin"
    File.join("usr", "//bin").should == "usr//bin"
  end

  it "joins parts using File::SEPARATOR if there are no boundary separators" do
    File.join("usr", "bin").should == "usr/bin"
  end

  it "prefers the separator of the right part if both parts have separators" do
    File.join("usr/", "//bin").should == "usr//bin"
    File.join("usr//", "/bin").should == "usr/bin"
  end

  platform_is :windows do
    it "respects given separator if only one part has a boundary separator" do
      File.join("C:\\", 'windows').should == "C:\\windows"
      File.join("C:", "\\windows").should == "C:\\windows"
      File.join("\\\\", "usr").should == "\\\\usr"
    end

    it "prefers the separator of the right part if both parts have separators" do
      File.join("C:/", "\\windows").should == "C:\\windows"
      File.join("C:\\", "/windows").should == "C:/windows"
    end
  end

  platform_is_not :windows do
    it "does not treat \\ as a separator on non-Windows" do
      File.join("usr\\", 'bin').should == "usr\\/bin"
      File.join("usr", "\\bin").should == "usr/\\bin"
      File.join("usr/", "\\bin").should == "usr/\\bin"
      File.join("usr\\", "/bin").should == "usr\\/bin"
    end
  end

  it "returns an empty string when given no arguments" do
    File.join.should == ""
  end

  it "returns a duplicate string when given a single argument" do
    str = "usr"
    File.join(str).should == str
    File.join(str).should_not equal(str)
  end

  it "supports any number of arguments" do
    File.join("a", "b", "c", "d").should == "a/b/c/d"
  end

  it "flattens nested arrays" do
    File.join(["a", "b", "c"]).should == "a/b/c"
    File.join(["a", ["b", ["c"]]]).should == "a/b/c"
  end

  it "inserts the separator in between empty strings and arrays" do
    File.join("").should == ""
    File.join("", "").should == "/"
    File.join(["", ""]).should == "/"
    File.join("a", "").should == "a/"
    File.join("", "a").should == "/a"

    File.join([]).should == ""
    File.join([], []).should == "/"
    File.join([[], []]).should == "/"
    File.join("a", []).should == "a/"
    File.join([], "a").should == "/a"
  end

  it "handles leading parts edge cases" do
    File.join("/bin")     .should == "/bin"
    File.join("", "bin")  .should == "/bin"
    File.join("/", "bin") .should == "/bin"
    File.join("/", "/bin").should == "/bin"
  end

  it "handles trailing parts edge cases" do
    File.join("bin", "")  .should == "bin/"
    File.join("bin/")     .should == "bin/"
    File.join("bin/", "") .should == "bin/"
    File.join("bin", "/") .should == "bin/"
    File.join("bin/", "/").should == "bin/"
  end

  it "handles middle parts edge cases" do
    File.join("usr",   "", "bin") .should == "usr/bin"
    File.join("usr/",  "", "bin") .should == "usr/bin"
    File.join("usr",   "", "/bin").should == "usr/bin"
    File.join("usr/",  "", "/bin").should == "usr/bin"
  end

  # TODO: See MRI svn r23306. Add patchlevel when there is a release.
  it "raises an ArgumentError if passed a recursive array" do
    a = ["a"]
    a << a
    -> { File.join a }.should raise_error(ArgumentError)
  end

  it "raises a TypeError exception when args are nil" do
    -> { File.join nil }.should raise_error(TypeError)
  end

  it "calls #to_str" do
    -> { File.join(mock('x')) }.should raise_error(TypeError)

    bin = mock("bin")
    bin.should_receive(:to_str).exactly(:twice).and_return("bin")
    File.join(bin).should == "bin"
    File.join("usr", bin).should == "usr/bin"
  end

  it "doesn't mutate the object when calling #to_str" do
    usr = mock("usr")
    str = "usr"
    usr.should_receive(:to_str).and_return(str)
    File.join(usr, "bin").should == "usr/bin"
    str.should == "usr"
  end

  it "calls #to_path" do
    -> { File.join(mock('x')) }.should raise_error(TypeError)

    bin = mock("bin")
    bin.should_receive(:to_path).exactly(:twice).and_return("bin")
    File.join(bin).should == "bin"
    File.join("usr", bin).should == "usr/bin"
  end

  it "raises errors for null bytes" do
    -> { File.join("\x00x", "metadata.gz") }.should raise_error(ArgumentError) { |e|
      e.message.should == 'string contains null byte'
    }
    -> { File.join("metadata.gz", "\x00x") }.should raise_error(ArgumentError) { |e|
      e.message.should == 'string contains null byte'
    }
  end
end