| // RUN: %target-run-simple-swift %t |
| // REQUIRES: executable_test |
| // UNSUPPORTED: OS=windows-msvc |
| |
| import StdlibUnittest |
| #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) |
| import Darwin |
| #elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) |
| import Glibc |
| #else |
| #error("Unsupported platform") |
| #endif |
| |
| chdir(CommandLine.arguments[1]) |
| |
| var POSIXTests = TestSuite("POSIXTests") |
| |
| let semaphoreName = "TestSem" |
| #if os(Android) |
| // In Android, the cwd is the root directory, which is not writable. |
| let fn: String = { |
| let capacity = Int(PATH_MAX) |
| let resolvedPath = UnsafeMutablePointer<Int8>.allocate(capacity: capacity) |
| resolvedPath.initialize(repeating: 0, count: capacity) |
| defer { |
| resolvedPath.deinitialize(count: capacity) |
| resolvedPath.deallocate() |
| } |
| guard let _ = realpath("/proc/self/exe", resolvedPath) else { |
| fatalError("Couldn't obtain executable path") |
| } |
| |
| let length = strlen(resolvedPath) |
| precondition(length != 0, "Couldn't obtain valid executable path") |
| |
| // Search backwards for the last /, and turn it into a null byte. |
| for idx in stride(from: length-1, through: 0, by: -1) { |
| if Unicode.Scalar(UInt8(resolvedPath[idx])) == Unicode.Scalar("/") { |
| resolvedPath[idx] = 0 |
| break |
| } |
| |
| precondition(idx != 0, "Couldn't obtain valid executable directory") |
| } |
| |
| return String(cString: resolvedPath) + "/test.txt" |
| }() |
| #else |
| let fn = "test.txt" |
| #endif |
| |
| POSIXTests.setUp { |
| sem_unlink(semaphoreName) |
| unlink(fn) |
| } |
| |
| // Failed semaphore creation. |
| #if !os(Android) // Android doesn’t implement sem_open and always return ENOSYS |
| POSIXTests.test("sem_open fail") { |
| let sem = sem_open(semaphoreName, 0) |
| expectEqual(SEM_FAILED, sem) |
| expectEqual(ENOENT, errno) |
| } |
| #endif |
| |
| // Successful semaphore creation. |
| #if !os(Android) // Android doesn’t implement sem_open and always return ENOSYS |
| POSIXTests.test("sem_open success") { |
| let sem = sem_open(semaphoreName, O_CREAT, 0o777, 1) |
| expectNotEqual(SEM_FAILED, sem) |
| |
| let res = sem_close(sem) |
| expectEqual(0, res) |
| |
| let res2 = sem_unlink(semaphoreName) |
| expectEqual(0, res2) |
| } |
| #endif |
| |
| // Successful semaphore creation with O_EXCL. |
| #if !os(Android) // Android doesn’t implement sem_open and always return ENOSYS |
| POSIXTests.test("sem_open O_EXCL success") { |
| let sem = sem_open(semaphoreName, O_CREAT | O_EXCL, 0o777, 1) |
| expectNotEqual(SEM_FAILED, sem) |
| |
| let res = sem_close(sem) |
| expectEqual(0, res) |
| |
| let res2 = sem_unlink(semaphoreName) |
| expectEqual(0, res2) |
| } |
| #endif |
| |
| // Successful creation and re-obtaining of existing semaphore. |
| #if !os(Android) // Android doesn’t implement sem_open and always return ENOSYS |
| POSIXTests.test("sem_open existing") { |
| let sem = sem_open(semaphoreName, O_CREAT, 0o777, 1) |
| expectNotEqual(SEM_FAILED, sem) |
| |
| let sem2 = sem_open(semaphoreName, 0) |
| // Here, we'd like to test that the semaphores are the same, but it's quite |
| // difficult. |
| expectNotEqual(SEM_FAILED, sem2) |
| |
| let res = sem_close(sem) |
| expectEqual(0, res) |
| |
| let res2 = sem_unlink(semaphoreName) |
| expectEqual(0, res2) |
| } |
| #endif |
| |
| // Fail because the semaphore already exists. |
| #if !os(Android) // Android doesn’t implement sem_open and always return ENOSYS |
| POSIXTests.test("sem_open existing O_EXCL fail") { |
| let sem = sem_open(semaphoreName, O_CREAT, 0o777, 1) |
| expectNotEqual(SEM_FAILED, sem) |
| |
| let sem2 = sem_open(semaphoreName, O_CREAT | O_EXCL, 0o777, 1) |
| expectEqual(SEM_FAILED, sem2) |
| expectEqual(EEXIST, errno) |
| |
| let res = sem_close(sem) |
| expectEqual(0, res) |
| |
| let res2 = sem_unlink(semaphoreName) |
| expectEqual(0, res2) |
| } |
| #endif |
| |
| // Fail because the file descriptor is invalid. |
| POSIXTests.test("ioctl(CInt, UInt, CInt): fail") { |
| let fd = open(fn, 0) |
| expectEqual(-1, fd) |
| expectEqual(ENOENT, errno) |
| |
| // A simple check to verify that ioctl is available |
| let _ = ioctl(fd, 0, 0) |
| expectEqual(EBADF, errno) |
| } |
| |
| #if os(Linux) || os(Android) |
| // Successful creation of a socket and listing interfaces |
| POSIXTests.test("ioctl(CInt, UInt, UnsafeMutableRawPointer): listing interfaces success") { |
| // Create a socket |
| let sock = socket(PF_INET, 1, 0) |
| expectGT(Int(sock), 0) |
| |
| // List interfaces |
| var ic = ifconf() |
| let io = ioctl(sock, UInt(SIOCGIFCONF), &ic); |
| expectGE(io, 0) |
| |
| //Cleanup |
| let res = close(sock) |
| expectEqual(0, res) |
| } |
| #endif |
| |
| // Fail because file doesn't exist. |
| POSIXTests.test("fcntl(CInt, CInt): fail") { |
| let fd = open(fn, 0) |
| expectEqual(-1, fd) |
| expectEqual(ENOENT, errno) |
| |
| let _ = fcntl(fd, F_GETFL) |
| expectEqual(EBADF, errno) |
| } |
| |
| // Change modes on existing file. |
| POSIXTests.test("fcntl(CInt, CInt): F_GETFL/F_SETFL success with file") { |
| // Create and open file. |
| let fd = open(fn, O_CREAT, 0o666) |
| expectGT(Int(fd), 0) |
| |
| var flags = fcntl(fd, F_GETFL) |
| expectGE(Int(flags), 0) |
| |
| // Change to APPEND mode... |
| var rc = fcntl(fd, F_SETFL, O_APPEND) |
| expectEqual(0, rc) |
| |
| flags = fcntl(fd, F_GETFL) |
| expectEqual(flags | O_APPEND, flags) |
| |
| // Change back... |
| rc = fcntl(fd, F_SETFL, 0) |
| expectEqual(0, rc) |
| |
| flags = fcntl(fd, F_GETFL) |
| expectGE(Int(flags), 0) |
| |
| // Clean up... |
| rc = close(fd) |
| expectEqual(0, rc) |
| |
| rc = unlink(fn) |
| expectEqual(0, rc) |
| } |
| |
| POSIXTests.test("fcntl(CInt, CInt, CInt): block and unblocking sockets success") { |
| // Create socket, note: socket created by default in blocking mode... |
| let sock = socket(PF_INET, 1, 0) |
| expectGT(Int(sock), 0) |
| |
| var flags = fcntl(sock, F_GETFL) |
| expectGE(Int(flags), 0) |
| |
| // Change mode of socket to non-blocking... |
| var rc = fcntl(sock, F_SETFL, flags | O_NONBLOCK) |
| expectEqual(0, rc) |
| |
| flags = fcntl(sock, F_GETFL) |
| expectEqual((flags | O_NONBLOCK), flags) |
| |
| // Change back to blocking... |
| rc = fcntl(sock, F_SETFL, flags & ~O_NONBLOCK) |
| expectEqual(0, rc) |
| |
| flags = fcntl(sock, F_GETFL) |
| expectGE(Int(flags), 0) |
| |
| // Clean up... |
| rc = close(sock) |
| expectEqual(0, rc) |
| } |
| |
| POSIXTests.test("fcntl(CInt, CInt, UnsafeMutableRawPointer): locking and unlocking success") { |
| // Create the file and add data to it... |
| var fd = open(fn, O_CREAT | O_WRONLY, 0o666) |
| expectGT(Int(fd), 0) |
| |
| let data = "Testing 1 2 3" |
| let bytesWritten = write(fd, data, data.utf8.count) |
| expectEqual(data.utf8.count, bytesWritten) |
| |
| var rc = close(fd) |
| expectEqual(0, rc) |
| |
| // Re-open the file... |
| fd = open(fn, 0) |
| expectGT(Int(fd), 0) |
| |
| // Lock for reading... |
| var flck = flock() |
| flck.l_type = Int16(F_RDLCK) |
| #if os(Android) |
| // In Android l_len is __kernel_off_t which is not the same size as off_t in |
| // 64 bits. |
| flck.l_len = __kernel_off_t(data.utf8.count) |
| #else |
| flck.l_len = off_t(data.utf8.count) |
| #endif |
| rc = fcntl(fd, F_SETLK, &flck) |
| expectEqual(0, rc) |
| |
| // Unlock for reading... |
| flck = flock() |
| flck.l_type = Int16(F_UNLCK) |
| rc = fcntl(fd, F_SETLK, &flck) |
| expectEqual(0, rc) |
| |
| // Clean up... |
| rc = close(fd) |
| expectEqual(0, rc) |
| |
| rc = unlink(fn) |
| expectEqual(0, rc) |
| } |
| |
| runAllTests() |