Source file src/embed/internal/embedtest/embed_test.go

     1  // Copyright 2020 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package embedtest
     6  
     7  import (
     8  	"embed"
     9  	"io"
    10  	"reflect"
    11  	"testing"
    12  	"testing/fstest"
    13  )
    14  
    15  //go:embed testdata/h*.txt
    16  //go:embed c*.txt testdata/g*.txt
    17  var global embed.FS
    18  
    19  //go:embed c*txt
    20  var concurrency string
    21  
    22  //go:embed testdata/g*.txt
    23  var glass []byte
    24  
    25  func testFiles(t *testing.T, f embed.FS, name, data string) {
    26  	t.Helper()
    27  	d, err := f.ReadFile(name)
    28  	if err != nil {
    29  		t.Error(err)
    30  		return
    31  	}
    32  	if string(d) != data {
    33  		t.Errorf("read %v = %q, want %q", name, d, data)
    34  	}
    35  }
    36  
    37  func testString(t *testing.T, s, name, data string) {
    38  	t.Helper()
    39  	if s != data {
    40  		t.Errorf("%v = %q, want %q", name, s, data)
    41  	}
    42  }
    43  
    44  func testDir(t *testing.T, f embed.FS, name string, expect ...string) {
    45  	t.Helper()
    46  	dirs, err := f.ReadDir(name)
    47  	if err != nil {
    48  		t.Error(err)
    49  		return
    50  	}
    51  	var names []string
    52  	for _, d := range dirs {
    53  		name := d.Name()
    54  		if d.IsDir() {
    55  			name += "/"
    56  		}
    57  		names = append(names, name)
    58  	}
    59  	if !reflect.DeepEqual(names, expect) {
    60  		t.Errorf("readdir %v = %v, want %v", name, names, expect)
    61  	}
    62  }
    63  
    64  // Tests for issue 49514.
    65  var _ = '"'
    66  var _ = '\''
    67  var _ = '🦆'
    68  
    69  func TestGlobal(t *testing.T) {
    70  	testFiles(t, global, "concurrency.txt", "Concurrency is not parallelism.\n")
    71  	testFiles(t, global, "testdata/hello.txt", "hello, world\n")
    72  	testFiles(t, global, "testdata/glass.txt", "I can eat glass and it doesn't hurt me.\n")
    73  
    74  	if err := fstest.TestFS(global, "concurrency.txt", "testdata/hello.txt"); err != nil {
    75  		t.Fatal(err)
    76  	}
    77  
    78  	testString(t, concurrency, "concurrency", "Concurrency is not parallelism.\n")
    79  	testString(t, string(glass), "glass", "I can eat glass and it doesn't hurt me.\n")
    80  }
    81  
    82  //go:embed testdata
    83  var testDirAll embed.FS
    84  
    85  func TestDir(t *testing.T) {
    86  	all := testDirAll
    87  	testFiles(t, all, "testdata/hello.txt", "hello, world\n")
    88  	testFiles(t, all, "testdata/i/i18n.txt", "internationalization\n")
    89  	testFiles(t, all, "testdata/i/j/k/k8s.txt", "kubernetes\n")
    90  	testFiles(t, all, "testdata/ken.txt", "If a program is too slow, it must have a loop.\n")
    91  
    92  	testDir(t, all, ".", "testdata/")
    93  	testDir(t, all, "testdata/i", "i18n.txt", "j/")
    94  	testDir(t, all, "testdata/i/j", "k/")
    95  	testDir(t, all, "testdata/i/j/k", "k8s.txt")
    96  }
    97  
    98  var (
    99  	//go:embed testdata
   100  	testHiddenDir embed.FS
   101  
   102  	//go:embed testdata/*
   103  	testHiddenStar embed.FS
   104  )
   105  
   106  func TestHidden(t *testing.T) {
   107  	dir := testHiddenDir
   108  	star := testHiddenStar
   109  
   110  	t.Logf("//go:embed testdata")
   111  
   112  	testDir(t, dir, "testdata",
   113  		"-not-hidden/", "ascii.txt", "glass.txt", "hello.txt", "i/", "ken.txt")
   114  
   115  	t.Logf("//go:embed testdata/*")
   116  
   117  	testDir(t, star, "testdata",
   118  		"-not-hidden/", ".hidden/", "_hidden/", "ascii.txt", "glass.txt", "hello.txt", "i/", "ken.txt")
   119  
   120  	testDir(t, star, "testdata/.hidden",
   121  		"fortune.txt", "more/") // but not .more or _more
   122  }
   123  
   124  func TestUninitialized(t *testing.T) {
   125  	var uninitialized embed.FS
   126  	testDir(t, uninitialized, ".")
   127  	f, err := uninitialized.Open(".")
   128  	if err != nil {
   129  		t.Fatal(err)
   130  	}
   131  	defer f.Close()
   132  	fi, err := f.Stat()
   133  	if err != nil {
   134  		t.Fatal(err)
   135  	}
   136  	if !fi.IsDir() {
   137  		t.Errorf("in uninitialized embed.FS, . is not a directory")
   138  	}
   139  }
   140  
   141  var (
   142  	//go:embed "testdata/hello.txt"
   143  	helloT []T
   144  	//go:embed "testdata/hello.txt"
   145  	helloUint8 []uint8
   146  	//go:embed "testdata/hello.txt"
   147  	helloEUint8 []EmbedUint8
   148  	//go:embed "testdata/hello.txt"
   149  	helloBytes EmbedBytes
   150  	//go:embed "testdata/hello.txt"
   151  	helloString EmbedString
   152  )
   153  
   154  type T byte
   155  type EmbedUint8 uint8
   156  type EmbedBytes []byte
   157  type EmbedString string
   158  
   159  // golang.org/issue/47735
   160  func TestAliases(t *testing.T) {
   161  	all := testDirAll
   162  	want, e := all.ReadFile("testdata/hello.txt")
   163  	if e != nil {
   164  		t.Fatal("ReadFile:", e)
   165  	}
   166  	check := func(g any) {
   167  		got := reflect.ValueOf(g)
   168  		for i := 0; i < got.Len(); i++ {
   169  			if byte(got.Index(i).Uint()) != want[i] {
   170  				t.Fatalf("got %v want %v", got.Bytes(), want)
   171  			}
   172  		}
   173  	}
   174  	check(helloT)
   175  	check(helloUint8)
   176  	check(helloEUint8)
   177  	check(helloBytes)
   178  	check(helloString)
   179  }
   180  
   181  func TestOffset(t *testing.T) {
   182  	file, err := testDirAll.Open("testdata/hello.txt")
   183  	if err != nil {
   184  		t.Fatal("Open:", err)
   185  	}
   186  
   187  	want := "hello, world\n"
   188  
   189  	// Read the entire file.
   190  	got := make([]byte, len(want))
   191  	n, err := file.Read(got)
   192  	if err != nil {
   193  		t.Fatal("Read:", err)
   194  	}
   195  	if n != len(want) {
   196  		t.Fatal("Read:", n)
   197  	}
   198  	if string(got) != want {
   199  		t.Fatalf("Read: %q", got)
   200  	}
   201  
   202  	// Try to read one byte; confirm we're at the EOF.
   203  	var buf [1]byte
   204  	n, err = file.Read(buf[:])
   205  	if err != io.EOF {
   206  		t.Fatal("Read:", err)
   207  	}
   208  	if n != 0 {
   209  		t.Fatal("Read:", n)
   210  	}
   211  
   212  	// Use seek to get the offset at the EOF.
   213  	seeker := file.(io.Seeker)
   214  	off, err := seeker.Seek(0, io.SeekCurrent)
   215  	if err != nil {
   216  		t.Fatal("Seek:", err)
   217  	}
   218  	if off != int64(len(want)) {
   219  		t.Fatal("Seek:", off)
   220  	}
   221  
   222  	// Use ReadAt to read the entire file, ignoring the offset.
   223  	at := file.(io.ReaderAt)
   224  	got = make([]byte, len(want))
   225  	n, err = at.ReadAt(got, 0)
   226  	if err != nil {
   227  		t.Fatal("ReadAt:", err)
   228  	}
   229  	if n != len(want) {
   230  		t.Fatalf("ReadAt: got %d bytes, want %d bytes", n, len(want))
   231  	}
   232  	if string(got) != want {
   233  		t.Fatalf("ReadAt: got %q, want %q", got, want)
   234  	}
   235  
   236  	// Use ReadAt with non-zero offset.
   237  	off = int64(7)
   238  	want = want[off:]
   239  	got = make([]byte, len(want))
   240  	n, err = at.ReadAt(got, off)
   241  	if err != nil {
   242  		t.Fatal("ReadAt:", err)
   243  	}
   244  	if n != len(want) {
   245  		t.Fatalf("ReadAt: got %d bytes, want %d bytes", n, len(want))
   246  	}
   247  	if string(got) != want {
   248  		t.Fatalf("ReadAt: got %q, want %q", got, want)
   249  	}
   250  }
   251  

View as plain text