make_open_tests.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // This makes the open test suite. It tries to open a file (existing
  2. // or not existing) with all possible file modes and writes a test
  3. // matrix.
  4. //
  5. // The behaviour is as run on Linux, with the small modification that
  6. // O_TRUNC with O_RDONLY does **not** truncate the file.
  7. //
  8. // Run with go generate (defined in vfs.go)
  9. //
  10. //go:build none
  11. // FIXME include read too?
  12. package main
  13. import (
  14. "fmt"
  15. "io"
  16. "log"
  17. "os"
  18. "strings"
  19. "github.com/rclone/rclone/lib/file"
  20. )
  21. // Interprets err into a vfs error
  22. func whichError(err error) string {
  23. switch err {
  24. case nil:
  25. return "nil"
  26. case io.EOF:
  27. return "io.EOF"
  28. case os.ErrInvalid:
  29. return "EINVAL"
  30. }
  31. s := err.Error()
  32. switch {
  33. case strings.Contains(s, "no such file or directory"):
  34. return "ENOENT"
  35. case strings.Contains(s, "bad file descriptor"):
  36. return "EBADF"
  37. case strings.Contains(s, "file exists"):
  38. return "EEXIST"
  39. }
  40. log.Fatalf("Unknown error: %v", err)
  41. return ""
  42. }
  43. const accessModeMask = (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)
  44. // test Opening, reading and writing the file handle with the flags given
  45. func test(fileName string, flags int, mode string) {
  46. // first try with file not existing
  47. _, err := os.Stat(fileName)
  48. if !os.IsNotExist(err) {
  49. log.Fatalf("File must not exist")
  50. }
  51. f, openNonExistentErr := file.OpenFile(fileName, flags, 0666)
  52. var readNonExistentErr error
  53. var writeNonExistentErr error
  54. if openNonExistentErr == nil {
  55. // read some bytes
  56. buf := []byte{0, 0}
  57. _, readNonExistentErr = f.Read(buf)
  58. // write some bytes
  59. _, writeNonExistentErr = f.Write([]byte("hello"))
  60. // close
  61. err = f.Close()
  62. if err != nil {
  63. log.Fatalf("failed to close: %v", err)
  64. }
  65. }
  66. // write the file
  67. f, err = file.Create(fileName)
  68. if err != nil {
  69. log.Fatalf("failed to create: %v", err)
  70. }
  71. n, err := f.Write([]byte("hello"))
  72. if n != 5 || err != nil {
  73. log.Fatalf("failed to write n=%d: %v", n, err)
  74. }
  75. // close
  76. err = f.Close()
  77. if err != nil {
  78. log.Fatalf("failed to close: %v", err)
  79. }
  80. // then open file and try with file existing
  81. f, openExistingErr := file.OpenFile(fileName, flags, 0666)
  82. var readExistingErr error
  83. var writeExistingErr error
  84. if openExistingErr == nil {
  85. // read some bytes
  86. buf := []byte{0, 0}
  87. _, readExistingErr = f.Read(buf)
  88. // write some bytes
  89. _, writeExistingErr = f.Write([]byte("HEL"))
  90. // close
  91. err = f.Close()
  92. if err != nil {
  93. log.Fatalf("failed to close: %v", err)
  94. }
  95. }
  96. // read the file
  97. f, err = file.Open(fileName)
  98. if err != nil {
  99. log.Fatalf("failed to open: %v", err)
  100. }
  101. var buf = make([]byte, 64)
  102. n, err = f.Read(buf)
  103. if err != nil && err != io.EOF {
  104. log.Fatalf("failed to read n=%d: %v", n, err)
  105. }
  106. err = f.Close()
  107. if err != nil {
  108. log.Fatalf("failed to close: %v", err)
  109. }
  110. contents := string(buf[:n])
  111. // remove file
  112. err = os.Remove(fileName)
  113. if err != nil {
  114. log.Fatalf("failed to remove: %v", err)
  115. }
  116. // http://pubs.opengroup.org/onlinepubs/7908799/xsh/open.html
  117. // The result of using O_TRUNC with O_RDONLY is undefined.
  118. // Linux seems to truncate the file, but we prefer to return EINVAL
  119. if (flags&accessModeMask) == os.O_RDONLY && flags&os.O_TRUNC != 0 {
  120. openNonExistentErr = os.ErrInvalid // EINVAL
  121. readNonExistentErr = nil
  122. writeNonExistentErr = nil
  123. openExistingErr = os.ErrInvalid // EINVAL
  124. readExistingErr = nil
  125. writeExistingErr = nil
  126. contents = "hello"
  127. }
  128. // output the struct
  129. fmt.Printf(`{
  130. flags: %s,
  131. what: %q,
  132. openNonExistentErr: %s,
  133. readNonExistentErr: %s,
  134. writeNonExistentErr: %s,
  135. openExistingErr: %s,
  136. readExistingErr: %s,
  137. writeExistingErr: %s,
  138. contents: %q,
  139. },`,
  140. mode,
  141. mode,
  142. whichError(openNonExistentErr),
  143. whichError(readNonExistentErr),
  144. whichError(writeNonExistentErr),
  145. whichError(openExistingErr),
  146. whichError(readExistingErr),
  147. whichError(writeExistingErr),
  148. contents)
  149. }
  150. func main() {
  151. fmt.Printf(`// Code generated by make_open_tests.go - use go generate to rebuild - DO NOT EDIT
  152. package vfs
  153. import (
  154. "os"
  155. "io"
  156. )
  157. // openTest describes a test of OpenFile
  158. type openTest struct{
  159. flags int
  160. what string
  161. openNonExistentErr error
  162. readNonExistentErr error
  163. writeNonExistentErr error
  164. openExistingErr error
  165. readExistingErr error
  166. writeExistingErr error
  167. contents string
  168. }
  169. // openTests is a suite of tests for OpenFile with all possible
  170. // combination of flags. This obeys Unix semantics even on Windows.
  171. var openTests = []openTest{
  172. `)
  173. f, err := os.CreateTemp("", "open-test")
  174. if err != nil {
  175. log.Fatal(err)
  176. }
  177. fileName := f.Name()
  178. _ = f.Close()
  179. err = os.Remove(fileName)
  180. if err != nil {
  181. log.Fatalf("failed to remove: %v", err)
  182. }
  183. for _, rwMode := range []int{os.O_RDONLY, os.O_WRONLY, os.O_RDWR} {
  184. flags0 := rwMode
  185. parts0 := []string{"os.O_RDONLY", "os.O_WRONLY", "os.O_RDWR"}[rwMode : rwMode+1]
  186. for _, appendMode := range []int{0, os.O_APPEND} {
  187. flags1 := flags0 | appendMode
  188. parts1 := parts0
  189. if appendMode != 0 {
  190. parts1 = append(parts1, "os.O_APPEND")
  191. }
  192. for _, createMode := range []int{0, os.O_CREATE} {
  193. flags2 := flags1 | createMode
  194. parts2 := parts1
  195. if createMode != 0 {
  196. parts2 = append(parts2, "os.O_CREATE")
  197. }
  198. for _, exclMode := range []int{0, os.O_EXCL} {
  199. flags3 := flags2 | exclMode
  200. parts3 := parts2
  201. if exclMode != 0 {
  202. parts3 = append(parts2, "os.O_EXCL")
  203. }
  204. for _, syncMode := range []int{0, os.O_SYNC} {
  205. flags4 := flags3 | syncMode
  206. parts4 := parts3
  207. if syncMode != 0 {
  208. parts4 = append(parts4, "os.O_SYNC")
  209. }
  210. for _, truncMode := range []int{0, os.O_TRUNC} {
  211. flags5 := flags4 | truncMode
  212. parts5 := parts4
  213. if truncMode != 0 {
  214. parts5 = append(parts5, "os.O_TRUNC")
  215. }
  216. textMode := strings.Join(parts5, "|")
  217. flags := flags5
  218. test(fileName, flags, textMode)
  219. }
  220. }
  221. }
  222. }
  223. }
  224. }
  225. fmt.Printf("\n}\n")
  226. }