1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package main

// Run with (the tool is not a workspace module; it is built only by Nix):
//
//	cd nix/buildGo/mkembedcfg && GOWORK=off go test main.go main_test.go

import (
	"reflect"
	"strings"
	"testing"
	"testing/fstest"
)

// tree mirrors the shapes the old guesser got wrong: a directory pattern with
// a nested subdirectory, hidden and underscore files, and a nested module.
func tree() fstest.MapFS {
	f := func(s string) *fstest.MapFile { return &fstest.MapFile{Data: []byte(s)} }
	return fstest.MapFS{
		"main.go":              f("package main"),
		"static/a.css":         f("a"),
		"static/sub/b.js":      f("b"),
		"static/.hidden":       f("h"),
		"static/_draft.css":    f("d"),
		"static/.git/config":   f("g"),
		"static/nested/go.mod": f("module n"),
		"static/nested/x.txt":  f("x"),
		"templates/i.html":     f("i"),
		"templates/j.html":     f("j"),
		"templates/k.txt":      f("k"),
		"empty/.only-hidden":   f("e"),
	}
}

func TestResolve(t *testing.T) {
	cases := []struct {
		pattern string
		want    []string
	}{
		// The old guesser matched static/* only and dropped static/sub/b.js.
		{"static", []string{"static/a.css", "static/sub/b.js"}},
		// all: keeps hidden and underscore names, still stops at a module.
		{"all:static", []string{"static/.git/config", "static/.hidden", "static/_draft.css", "static/a.css", "static/sub/b.js"}},
		{"templates/*.html", []string{"templates/i.html", "templates/j.html"}},
		{"templates/i.html", []string{"templates/i.html"}},
		// A hidden file named explicitly is embedded, as with go build.
		{"static/.hidden", []string{"static/.hidden"}},
	}
	for _, c := range cases {
		cfg, err := resolve(tree(), "/src", []string{c.pattern})
		if err != nil {
			t.Errorf("%s: %v", c.pattern, err)
			continue
		}
		if got := cfg.Patterns[c.pattern]; !reflect.DeepEqual(got, c.want) {
			t.Errorf("%s = %v, want %v", c.pattern, got, c.want)
		}
		for _, f := range c.want {
			if cfg.Files[f] != "/src/"+f {
				t.Errorf("%s: Files[%s] = %q, want /src/%s", c.pattern, f, cfg.Files[f], f)
			}
		}
	}
}

// TestResolveErrors pins that a pattern embedding nothing fails, where the
// old tool mapped it to every embedded file and built successfully.
func TestResolveErrors(t *testing.T) {
	cases := map[string]string{
		"templates/*.htm": "no matching files",
		"missing":         "no matching files",
		"empty":           "contains no embeddable files",
		".":               "invalid pattern",
		"../escape":       "invalid pattern",
	}
	for pattern, want := range cases {
		_, err := resolve(tree(), "/src", []string{pattern})
		if err == nil || !strings.Contains(err.Error(), want) {
			t.Errorf("%s: err = %v, want containing %q", pattern, err, want)
		}
	}
}

// TestResolveUnion checks Files is the union over patterns, as go build's is.
func TestResolveUnion(t *testing.T) {
	cfg, err := resolve(tree(), "/src", []string{"templates/*.html", "templates/i.html", "static"})
	if err != nil {
		t.Fatal(err)
	}
	if len(cfg.Files) != 4 {
		t.Errorf("Files has %d entries, want 4: %v", len(cfg.Files), cfg.Files)
	}
}