github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/vfs/mem_fs_test.go (about)

     1  // Copyright 2012 The LevelDB-Go and Pebble Authors. All rights reserved. Use
     2  // of this source code is governed by a BSD-style license that can be found in
     3  // the LICENSE file.
     4  
     5  package vfs
     6  
     7  import (
     8  	"io"
     9  	"os"
    10  	"sort"
    11  	"strconv"
    12  	"strings"
    13  	"testing"
    14  )
    15  
    16  func normalize(name string) string {
    17  	if os.PathSeparator == '/' {
    18  		return name
    19  	}
    20  	return strings.Replace(name, "/", string(os.PathSeparator), -1)
    21  }
    22  
    23  func TestBasics(t *testing.T) {
    24  	fs := NewMem()
    25  	testCases := []string{
    26  		// Create a top-level file.
    27  		"1a: create /foo",
    28  		// Create a child of that file. It should fail, since /foo is not a directory.
    29  		"2a: create /foo/x fails",
    30  		// Create a third-level file. It should fail, since /bar has not been created.
    31  		// Similarly, opening that file should fail.
    32  		"3a: create /bar/baz/y fails",
    33  		"3b: open /bar/baz/y fails",
    34  		// Make the /bar/baz directory; create a third-level file. Creation should now succeed.
    35  		"4a: mkdirall /bar/baz",
    36  		"4b: f = create /bar/baz/y",
    37  		"4c: f.stat.name == y",
    38  		// Write some data; read it back.
    39  		"5a: f.write abcde",
    40  		"5b: f.close",
    41  		"5c: f = open /bar/baz/y",
    42  		"5d: f.read 5 == abcde",
    43  		"5e: f.readat 2 1 == bc",
    44  		"5f: f.close",
    45  		// Link /bar/baz/y to /bar/baz/z. We should be able to read from both files
    46  		// and remove them independently.
    47  		"6a: link /bar/baz/y /bar/baz/z",
    48  		"6b: f = open /bar/baz/z",
    49  		"6c: f.read 5 == abcde",
    50  		"6d: f.close",
    51  		"6e: remove /bar/baz/z",
    52  		"6f: f = open /bar/baz/y",
    53  		"6g: f.read 5 == abcde",
    54  		"6h: f.close",
    55  		// Remove the file twice. The first should succeed, the second should fail.
    56  		"7a: remove /bar/baz/y",
    57  		"7b: remove /bar/baz/y fails",
    58  		"7c: open /bar/baz/y fails",
    59  		// Rename /foo to /goo. Trying to open /foo should succeed before the rename and
    60  		// fail afterwards, and vice versa for /goo.
    61  		"8a: open /foo",
    62  		"8b: open /goo fails",
    63  		"8c: rename /foo /goo",
    64  		"8d: open /foo fails",
    65  		"8e: open /goo",
    66  		// Create /bar/baz/z and rename /bar/baz to /bar/caz.
    67  		"9a: create /bar/baz/z",
    68  		"9b: open /bar/baz/z",
    69  		"9c: open /bar/caz/z fails",
    70  		"9d: rename /bar/baz /bar/caz",
    71  		"9e: open /bar/baz/z fails",
    72  		"9f: open /bar/caz/z",
    73  	}
    74  	var f File
    75  	for _, tc := range testCases {
    76  		s := strings.Split(tc, " ")[1:]
    77  
    78  		saveF := s[0] == "f" && s[1] == "="
    79  		if saveF {
    80  			s = s[2:]
    81  		}
    82  
    83  		fails := s[len(s)-1] == "fails"
    84  		if fails {
    85  			s = s[:len(s)-1]
    86  		}
    87  
    88  		var (
    89  			fi  os.FileInfo
    90  			g   File
    91  			err error
    92  		)
    93  		switch s[0] {
    94  		case "create":
    95  			g, err = fs.Create(normalize(s[1]))
    96  		case "link":
    97  			err = fs.Link(normalize(s[1]), normalize(s[2]))
    98  		case "open":
    99  			g, err = fs.Open(normalize(s[1]))
   100  		case "mkdirall":
   101  			err = fs.MkdirAll(normalize(s[1]), 0755)
   102  		case "remove":
   103  			err = fs.Remove(normalize(s[1]))
   104  		case "rename":
   105  			err = fs.Rename(normalize(s[1]), normalize(s[2]))
   106  		case "f.write":
   107  			_, err = f.Write([]byte(s[1]))
   108  		case "f.read":
   109  			n, _ := strconv.Atoi(s[1])
   110  			buf := make([]byte, n)
   111  			_, err = io.ReadFull(f, buf)
   112  			if err != nil {
   113  				break
   114  			}
   115  			if got, want := string(buf), s[3]; got != want {
   116  				t.Fatalf("%q: got %q, want %q", tc, got, want)
   117  			}
   118  		case "f.readat":
   119  			n, _ := strconv.Atoi(s[1])
   120  			off, _ := strconv.Atoi(s[2])
   121  			buf := make([]byte, n)
   122  			_, err = f.ReadAt(buf, int64(off))
   123  			if err != nil {
   124  				break
   125  			}
   126  			if got, want := string(buf), s[4]; got != want {
   127  				t.Fatalf("%q: got %q, want %q", tc, got, want)
   128  			}
   129  		case "f.close":
   130  			f, err = nil, f.Close()
   131  		case "f.stat.name":
   132  			fi, err = f.Stat()
   133  			if err != nil {
   134  				break
   135  			}
   136  			if got, want := fi.Name(), s[2]; got != want {
   137  				t.Fatalf("%q: got %q, want %q", tc, got, want)
   138  			}
   139  		default:
   140  			t.Fatalf("bad test case: %q", tc)
   141  		}
   142  
   143  		if saveF {
   144  			f, g = g, nil
   145  		} else if g != nil {
   146  			g.Close()
   147  		}
   148  
   149  		if fails {
   150  			if err == nil {
   151  				t.Fatalf("%q: got nil error, want non-nil", tc)
   152  			}
   153  		} else {
   154  			if err != nil {
   155  				t.Fatalf("%q: %v", tc, err)
   156  			}
   157  		}
   158  	}
   159  }
   160  
   161  func TestList(t *testing.T) {
   162  	fs := NewMem()
   163  
   164  	dirnames := []string{
   165  		"/bar",
   166  		"/foo/2",
   167  	}
   168  	for _, dirname := range dirnames {
   169  		err := fs.MkdirAll(normalize(dirname), 0755)
   170  		if err != nil {
   171  			t.Fatalf("MkdirAll %q: %v", dirname, err)
   172  		}
   173  	}
   174  
   175  	filenames := []string{
   176  		"/a",
   177  		"/bar/baz",
   178  		"/foo/0",
   179  		"/foo/1",
   180  		"/foo/2/a",
   181  		"/foo/2/b",
   182  		"/foo/3",
   183  		"/foot",
   184  	}
   185  	for _, filename := range filenames {
   186  		f, err := fs.Create(normalize(filename))
   187  		if err != nil {
   188  			t.Fatalf("Create %q: %v", filename, err)
   189  		}
   190  		if err := f.Close(); err != nil {
   191  			t.Fatalf("Close %q: %v", filename, err)
   192  		}
   193  	}
   194  
   195  	{
   196  		got := fs.(*memFS).String()
   197  		want := normalize(`          /
   198         0    a
   199              bar/
   200         0      baz
   201              foo/
   202         0      0
   203         0      1
   204                2/
   205         0        a
   206         0        b
   207         0      3
   208         0    foot
   209  `)
   210  		if got != want {
   211  			t.Fatalf("String:\n----got----\n%s----want----\n%s", got, want)
   212  		}
   213  	}
   214  
   215  	testCases := []string{
   216  		"/:a bar foo foot",
   217  		"/bar:baz",
   218  		"/bar/:baz",
   219  		"/baz:",
   220  		"/baz/:",
   221  		"/foo:0 1 2 3",
   222  		"/foo/:0 1 2 3",
   223  		"/foo/1:",
   224  		"/foo/1/:",
   225  		"/foo/2:a b",
   226  		"/foo/2/:a b",
   227  		"/foot:",
   228  		"/foot/:",
   229  	}
   230  	for _, tc := range testCases {
   231  		s := strings.Split(tc, ":")
   232  		list, _ := fs.List(normalize(s[0]))
   233  		sort.Strings(list)
   234  		got := strings.Join(list, " ")
   235  		want := s[1]
   236  		if got != want {
   237  			t.Errorf("List %q: got %q, want %q", s[0], got, want)
   238  		}
   239  	}
   240  }