basicfs_windows_test.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // Copyright (C) 2018 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. //go:build windows
  7. // +build windows
  8. package fs
  9. import (
  10. "os"
  11. "path/filepath"
  12. "strings"
  13. "testing"
  14. )
  15. func TestWindowsPaths(t *testing.T) {
  16. testCases := []struct {
  17. input string
  18. expectedRoot string
  19. expectedURI string
  20. }{
  21. {`e:\`, `\\?\e:\`, `e:\`},
  22. {`\\?\e:\`, `\\?\e:\`, `e:\`},
  23. {`\\192.0.2.22\network\share`, `\\192.0.2.22\network\share`, `\\192.0.2.22\network\share`},
  24. }
  25. for _, testCase := range testCases {
  26. fs := newBasicFilesystem(testCase.input)
  27. if fs.root != testCase.expectedRoot {
  28. t.Errorf("root %q != %q", fs.root, testCase.expectedRoot)
  29. }
  30. if fs.URI() != testCase.expectedURI {
  31. t.Errorf("uri %q != %q", fs.URI(), testCase.expectedURI)
  32. }
  33. }
  34. fs := newBasicFilesystem(`relative\path`)
  35. if fs.root == `relative\path` || !strings.HasPrefix(fs.root, "\\\\?\\") {
  36. t.Errorf("%q == %q, expected absolutification", fs.root, `relative\path`)
  37. }
  38. }
  39. func TestResolveWindows83(t *testing.T) {
  40. fs, dir := setup(t)
  41. if isMaybeWin83(dir) {
  42. dir = fs.resolveWin83(dir)
  43. fs = newBasicFilesystem(dir)
  44. }
  45. defer os.RemoveAll(dir)
  46. shortAbs, _ := fs.rooted("LFDATA~1")
  47. long := "LFDataTool"
  48. longAbs, _ := fs.rooted(long)
  49. deleted, _ := fs.rooted(filepath.Join("foo", "LFDATA~1"))
  50. notShort, _ := fs.rooted(filepath.Join("foo", "bar", "baz"))
  51. fd, err := fs.Create(long)
  52. if err != nil {
  53. t.Fatal(err)
  54. }
  55. fd.Close()
  56. if res := fs.resolveWin83(shortAbs); res != longAbs {
  57. t.Errorf(`Resolving for 8.3 names of "%v" resulted in "%v", expected "%v"`, shortAbs, res, longAbs)
  58. }
  59. if res := fs.resolveWin83(deleted); res != filepath.Dir(deleted) {
  60. t.Errorf(`Resolving for 8.3 names of "%v" resulted in "%v", expected "%v"`, deleted, res, filepath.Dir(deleted))
  61. }
  62. if res := fs.resolveWin83(notShort); res != notShort {
  63. t.Errorf(`Resolving for 8.3 names of "%v" resulted in "%v", expected "%v"`, notShort, res, notShort)
  64. }
  65. }
  66. func TestIsWindows83(t *testing.T) {
  67. fs, dir := setup(t)
  68. if isMaybeWin83(dir) {
  69. dir = fs.resolveWin83(dir)
  70. fs = newBasicFilesystem(dir)
  71. }
  72. defer os.RemoveAll(dir)
  73. tempTop, _ := fs.rooted(TempName("baz"))
  74. tempBelow, _ := fs.rooted(filepath.Join("foo", "bar", TempName("baz")))
  75. short, _ := fs.rooted(filepath.Join("LFDATA~1", TempName("baz")))
  76. tempAndShort, _ := fs.rooted(filepath.Join("LFDATA~1", TempName("baz")))
  77. for _, f := range []string{tempTop, tempBelow} {
  78. if isMaybeWin83(f) {
  79. t.Errorf(`"%v" is not a windows 8.3 path"`, f)
  80. }
  81. }
  82. for _, f := range []string{short, tempAndShort} {
  83. if !isMaybeWin83(f) {
  84. t.Errorf(`"%v" is not a windows 8.3 path"`, f)
  85. }
  86. }
  87. }
  88. func TestRelUnrootedCheckedWindows(t *testing.T) {
  89. testCases := []struct {
  90. root string
  91. abs string
  92. expectedRel string
  93. }{
  94. {`c:\`, `c:\foo`, `foo`},
  95. {`C:\`, `c:\foo`, `foo`},
  96. {`C:\`, `C:\foo`, `foo`},
  97. {`c:\`, `C:\foo`, `foo`},
  98. {`\\?c:\`, `\\?c:\foo`, `foo`},
  99. {`\\?C:\`, `\\?c:\foo`, `foo`},
  100. {`\\?C:\`, `\\?C:\foo`, `foo`},
  101. {`\\?c:\`, `\\?C:\foo`, `foo`},
  102. {`c:\foo`, `c:\foo\bar`, `bar`},
  103. {`c:\foo`, `c:\foo\bAr`, `bAr`},
  104. {`c:\foO`, `c:\Foo\bar`, `bar`},
  105. {`c:\foO`, `c:\fOo\bAr`, `bAr`},
  106. {`c:\foO`, `c:\fOo`, ``},
  107. {`C:\foO`, `c:\fOo`, ``},
  108. }
  109. for _, tc := range testCases {
  110. if res := rel(tc.abs, tc.root); res != tc.expectedRel {
  111. t.Errorf(`rel("%v", "%v") == "%v", expected "%v"`, tc.abs, tc.root, res, tc.expectedRel)
  112. }
  113. // unrootedChecked really just wraps rel, and does not care about
  114. // the actual root of that filesystem, but should not return an error
  115. // on these test cases.
  116. for _, root := range []string{tc.root, strings.ToLower(tc.root), strings.ToUpper(tc.root)} {
  117. fs := BasicFilesystem{root: root}
  118. if res, err := fs.unrootedChecked(tc.abs, []string{tc.root}); err != nil {
  119. t.Errorf(`Unexpected error from unrootedChecked("%v", "%v"): %v (fs.root: %v)`, tc.abs, tc.root, err, root)
  120. } else if res != tc.expectedRel {
  121. t.Errorf(`unrootedChecked("%v", "%v") == "%v", expected "%v" (fs.root: %v)`, tc.abs, tc.root, res, tc.expectedRel, root)
  122. }
  123. }
  124. }
  125. }
  126. // TestMultipleRoot checks that fs.unrootedChecked returns the correct path
  127. // when given more than one possible root path.
  128. func TestMultipleRoot(t *testing.T) {
  129. root := `c:\foO`
  130. roots := []string{root, `d:\`}
  131. rel := `bar`
  132. path := filepath.Join(root, rel)
  133. fs := BasicFilesystem{root: root}
  134. if res, err := fs.unrootedChecked(path, roots); err != nil {
  135. t.Errorf(`Unexpected error from unrootedChecked("%v", "%v"): %v (fs.root: %v)`, path, roots, err, root)
  136. } else if res != rel {
  137. t.Errorf(`unrootedChecked("%v", "%v") == "%v", expected "%v" (fs.root: %v)`, path, roots, res, rel, root)
  138. }
  139. }
  140. func TestGetFinalPath(t *testing.T) {
  141. testCases := []struct {
  142. input string
  143. expectedPath string
  144. eqToEvalSyml bool
  145. ignoreMissing bool
  146. }{
  147. {`c:\`, `C:\`, true, false},
  148. {`\\?\c:\`, `C:\`, false, false},
  149. {`c:\wInDows\sYstEm32`, `C:\Windows\System32`, true, false},
  150. {`c:\parent\child`, `C:\parent\child`, false, true},
  151. }
  152. for _, testCase := range testCases {
  153. out, err := getFinalPathName(testCase.input)
  154. if err != nil {
  155. if testCase.ignoreMissing && os.IsNotExist(err) {
  156. continue
  157. }
  158. t.Errorf("getFinalPathName failed at %q with error %s", testCase.input, err)
  159. }
  160. // Trim UNC prefix
  161. if strings.HasPrefix(out, `\\?\UNC\`) {
  162. out = `\` + out[7:]
  163. } else {
  164. out = strings.TrimPrefix(out, `\\?\`)
  165. }
  166. if out != testCase.expectedPath {
  167. t.Errorf("getFinalPathName got wrong path: %q (expected %q)", out, testCase.expectedPath)
  168. }
  169. if testCase.eqToEvalSyml {
  170. evlPath, err1 := filepath.EvalSymlinks(testCase.input)
  171. if err1 != nil || out != evlPath {
  172. t.Errorf("EvalSymlinks got different results %q %s", evlPath, err1)
  173. }
  174. }
  175. }
  176. }