2 // readlink() / readlinkat() Test Cases
5 // Steffen Kiess (s-kiess@web.de)
7 // Copyright (C) 2013 Steffen Kiess
15 using Mono.Unix.Native;
17 using NUnit.Framework;
19 namespace MonoTests.Mono.Unix
21 [TestFixture, Category ("NotDotNet"), Category ("NotOnWindows")]
22 public class ReadlinkTest {
24 static string[] Targets = {
28 // With non-ASCII characters
31 // With non-UTF8 bytes
32 UnixEncoding.Instance.GetString (new byte[] {0xff, 0x80, 0x41, 0x80}),
33 // Size is roughly initial size of buffer
34 new string ('a', 255),
35 new string ('a', 256),
36 new string ('a', 257),
37 // With non-ASCII characters, size is roughly initial size of buffer
38 "ä" + new string ('a', 253), // 254 chars, 255 bytes
39 "ä" + new string ('a', 254), // 255 chars, 256 bytes
40 "ä" + new string ('a', 255), // 256 chars, 257 bytes
41 "ä" + new string ('a', 256), // 257 chars, 258 bytes
42 new string ('a', 253) + "ä", // 254 chars, 255 bytes
43 new string ('a', 254) + "ä", // 255 chars, 256 bytes
44 new string ('a', 255) + "ä", // 256 chars, 257 bytes
45 new string ('a', 256) + "ä", // 257 chars, 258 bytes
46 // With non-UTF8 bytes, size is roughly initial size of buffer
47 "\0\u00ff" + new string ('a', 253), // 255 chars, 254 bytes
48 "\0\u00ff" + new string ('a', 254), // 256 chars, 255 bytes
49 "\0\u00ff" + new string ('a', 255), // 257 chars, 256 bytes
50 "\0\u00ff" + new string ('a', 256), // 258 chars, 257 bytes
51 new string ('a', 253) + "\0\u00ff", // 255 chars, 254 bytes
52 new string ('a', 254) + "\0\u00ff", // 256 chars, 255 bytes
53 new string ('a', 255) + "\0\u00ff", // 257 chars, 256 bytes
54 new string ('a', 256) + "\0\u00ff", // 258 chars, 257 bytes
64 HaveReadlinkAt = false;
66 Syscall.readlinkat (-1, "", new byte[1]);
67 HaveReadlinkAt = true;
68 } catch (EntryPointNotFoundException) {
72 TempFolder = Path.Combine (Path.GetTempPath (), this.GetType ().FullName);
74 if (Directory.Exists (TempFolder))
75 //Directory.Delete (TempFolder, true); // Fails for long link target paths
76 new UnixDirectoryInfo (TempFolder).Delete (true);
78 Directory.CreateDirectory (TempFolder);
80 TempFD = Syscall.open (TempFolder, OpenFlags.O_RDONLY | OpenFlags.O_DIRECTORY);
82 UnixMarshal.ThrowExceptionForLastError ();
86 public void TearDown()
88 if (Syscall.close (TempFD) < 0)
89 UnixMarshal.ThrowExceptionForLastError ();
91 if (Directory.Exists (TempFolder))
92 //Directory.Delete (TempFolder, true); // Fails for long link target paths
93 new UnixDirectoryInfo (TempFolder).Delete (true);
96 void CreateLink (string s)
98 string link = UnixPath.Combine (TempFolder, "link");
100 //File.Delete (link); // Fails for long link target paths
101 if (Syscall.unlink (link) < 0 && Stdlib.GetLastError () != Errno.ENOENT)
102 UnixMarshal.ThrowExceptionForLastError ();
104 if (Syscall.symlink (s, link) < 0)
105 UnixMarshal.ThrowExceptionForLastError ();
109 public void ReadLink ()
111 foreach (string s in Targets) {
112 string link = UnixPath.Combine (TempFolder, "link");
116 var target = UnixPath.ReadLink (link);
117 Assert.AreEqual (s, target);
122 public void ReadLinkAt ()
125 Assert.Ignore ("No ReadlinkAt.");
127 foreach (string s in Targets) {
130 var target = UnixPath.ReadLinkAt (TempFD, "link");
131 Assert.AreEqual (s, target);
136 public void TryReadLink ()
138 foreach (string s in Targets) {
139 string link = UnixPath.Combine (TempFolder, "link");
143 var target = UnixPath.TryReadLink (link);
144 Assert.AreEqual (s, target);
149 public void TryReadLinkAt ()
152 Assert.Ignore ("No ReadlinkAt.");
154 foreach (string s in Targets) {
157 var target = UnixPath.TryReadLinkAt (TempFD, "link");
158 Assert.AreEqual (s, target);
163 public void readlink_byte ()
165 foreach (string s in Targets) {
166 string link = UnixPath.Combine (TempFolder, "link");
170 string target = null;
171 byte[] buf = new byte[256];
173 long r = Syscall.readlink (link, buf);
175 UnixMarshal.ThrowExceptionForLastError ();
176 Assert.That(buf.Length, Is.GreaterThanOrEqualTo(r));
178 buf = new byte[checked (buf.Length * 2)];
180 target = UnixEncoding.Instance.GetString (buf, 0, checked ((int) r));
181 } while (target == null);
183 Assert.AreEqual (s, target);
188 public void readlinkat_byte ()
191 Assert.Ignore ("No ReadlinkAt.");
193 foreach (string s in Targets) {
196 string target = null;
197 byte[] buf = new byte[256];
199 long r = Syscall.readlinkat (TempFD, "link", buf);
201 UnixMarshal.ThrowExceptionForLastError ();
202 Assert.That(buf.Length, Is.GreaterThanOrEqualTo(r));
204 buf = new byte[checked (buf.Length * 2)];
206 target = UnixEncoding.Instance.GetString (buf, 0, checked ((int) r));
207 } while (target == null);
209 Assert.AreEqual (s, target);
214 public void readlink_char ()
216 foreach (string s in Targets) {
217 string link = UnixPath.Combine (TempFolder, "link");
221 var sb = new StringBuilder (256);
223 int oldCapacity = sb.Capacity;
224 int r = Syscall.readlink (link, sb);
225 Assert.AreEqual (oldCapacity, sb.Capacity);
227 UnixMarshal.ThrowExceptionForLastError ();
228 Assert.AreEqual (r, sb.Length);
229 Assert.That(sb.Capacity, Is.GreaterThanOrEqualTo(r));
230 if (r == sb.Capacity)
231 checked { sb.Capacity *= 2; }
235 var target = sb.ToString ();
237 Assert.AreEqual (s, target);
242 public void readlinkat_char ()
245 Assert.Ignore ("No ReadlinkAt.");
247 foreach (string s in Targets) {
250 var sb = new StringBuilder (256);
252 int oldCapacity = sb.Capacity;
253 int r = Syscall.readlinkat (TempFD, "link", sb);
254 Assert.AreEqual (oldCapacity, sb.Capacity);
256 UnixMarshal.ThrowExceptionForLastError ();
257 Assert.AreEqual (r, sb.Length);
258 Assert.That(sb.Capacity, Is.GreaterThanOrEqualTo(r));
259 if (r == sb.Capacity)
260 checked { sb.Capacity *= 2; }
264 var target = sb.ToString ();
266 Assert.AreEqual (s, target);
271 public void ReadlinkMultiByteChar ()
273 string link = UnixPath.Combine (TempFolder, "link");
277 var sb = new StringBuilder (2);
278 int res = Syscall.readlink (link, sb);
280 UnixMarshal.ThrowExceptionForLastError ();
282 Assert.AreEqual (res, 2);
283 Assert.AreEqual (sb.Length, 2);
284 Assert.AreEqual (sb.Capacity, 2);
285 Assert.AreEqual (sb.ToString (), "á\u0000");