make_open_tests.go 5.7 KB

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