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

View as plain text