1// Copyright 2020 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// +build go1.15
16
17package main
18
19import (
20	"flag"
21	"io/ioutil"
22	"os"
23	"path/filepath"
24	"testing"
25
26	_ "cloud.google.com/go/bigquery" // Implicitly required by test.
27	_ "cloud.google.com/go/storage"  // Implicitly required by test.
28)
29
30var updateGoldens bool
31
32func TestMain(m *testing.M) {
33	flag.BoolVar(&updateGoldens, "update-goldens", false, "Update the golden files")
34	flag.Parse()
35	os.Exit(m.Run())
36}
37
38func TestParse(t *testing.T) {
39	mod := "cloud.google.com/go/bigquery"
40	r, err := parse(mod+"/...", ".", []string{"README.md"})
41	if err != nil {
42		t.Fatalf("Parse: %v", err)
43	}
44	if got, want := len(r.toc), 1; got != want {
45		t.Fatalf("Parse got len(toc) = %d, want %d", got, want)
46	}
47	if got, want := len(r.pages), 10; got != want {
48		t.Errorf("Parse got len(pages) = %d, want %d", got, want)
49	}
50	if got := r.module.Path; got != mod {
51		t.Fatalf("Parse got module = %q, want %q", got, mod)
52	}
53
54	page := r.pages[mod]
55
56	// Check invariants for every item.
57	for _, item := range page.Items {
58		if got := item.UID; got == "" {
59			t.Errorf("Parse found missing UID: %v", item)
60		}
61
62		if got, want := item.Langs, []string{"go"}; len(got) != 1 || got[0] != want[0] {
63			t.Errorf("Parse %v got langs = %v, want %v", item.UID, got, want)
64		}
65	}
66
67	// Check there is at least one type, const, variable, function, and method.
68	wants := []string{"type", "const", "variable", "function", "method"}
69	for _, want := range wants {
70		found := false
71		for _, c := range page.Items {
72			if c.Type == want {
73				found = true
74				break
75			}
76		}
77		if !found {
78			t.Errorf("Parse got no %q, want at least one", want)
79		}
80	}
81
82	foundREADME := false
83	foundUnnested := false
84	for _, item := range r.toc[0].Items {
85		if item.Name == "README" {
86			foundREADME = true
87		}
88		if len(item.Items) == 0 && len(item.UID) > 0 && len(item.Name) > 0 {
89			foundUnnested = true
90		}
91	}
92	if !foundREADME {
93		t.Errorf("Parse didn't find a README in TOC")
94	}
95	if !foundUnnested {
96		t.Errorf("Parse didn't find an unnested element in TOC (e.g. datatransfer/apiv1)")
97	}
98}
99
100func TestGoldens(t *testing.T) {
101	gotDir := "testdata/out"
102	goldenDir := "testdata/golden"
103	extraFiles := []string{"README.md"}
104
105	testPath := "cloud.google.com/go/storage"
106	r, err := parse(testPath, ".", extraFiles)
107	if err != nil {
108		t.Fatalf("parse: %v", err)
109	}
110
111	ignoreFiles := map[string]bool{"docs.metadata": true}
112
113	if updateGoldens {
114		os.RemoveAll(goldenDir)
115
116		if err := write(goldenDir, r); err != nil {
117			t.Fatalf("write: %v", err)
118		}
119
120		for ignore := range ignoreFiles {
121			if err := os.Remove(filepath.Join(goldenDir, ignore)); err != nil {
122				t.Fatalf("Remove: %v", err)
123			}
124		}
125
126		t.Logf("Successfully updated goldens in %s", goldenDir)
127
128		return
129	}
130
131	if err := write(gotDir, r); err != nil {
132		t.Fatalf("write: %v", err)
133	}
134
135	gotFiles, err := ioutil.ReadDir(gotDir)
136	if err != nil {
137		t.Fatalf("ReadDir: %v", err)
138	}
139
140	goldens, err := ioutil.ReadDir(goldenDir)
141	if err != nil {
142		t.Fatalf("ReadDir: %v", err)
143	}
144
145	if got, want := len(gotFiles)-len(ignoreFiles), len(goldens); got != want {
146		t.Fatalf("parse & write got %d files in %s, want %d ignoring %v", got, gotDir, want, ignoreFiles)
147	}
148
149	for _, golden := range goldens {
150		if golden.IsDir() {
151			continue
152		}
153		gotPath := filepath.Join(gotDir, golden.Name())
154		goldenPath := filepath.Join(goldenDir, golden.Name())
155
156		gotContent, err := ioutil.ReadFile(gotPath)
157		if err != nil {
158			t.Fatalf("ReadFile: %v", err)
159		}
160
161		goldenContent, err := ioutil.ReadFile(goldenPath)
162		if err != nil {
163			t.Fatalf("ReadFile: %v", err)
164		}
165
166		if string(gotContent) != string(goldenContent) {
167			t.Errorf("got %s is different from expected %s", gotPath, goldenPath)
168		}
169	}
170}
171