1// Copyright 2018 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
5package godoc
6
7import (
8	"go/build"
9	"testing"
10)
11
12func TestParseVersionRow(t *testing.T) {
13	tests := []struct {
14		row  string
15		want versionedRow
16	}{
17		{
18			row: "# comment",
19		},
20		{
21			row: "",
22		},
23		{
24			row: "pkg archive/tar, type Writer struct",
25			want: versionedRow{
26				pkg:  "archive/tar",
27				kind: "type",
28				name: "Writer",
29			},
30		},
31		{
32			row: "pkg archive/tar, type Header struct, AccessTime time.Time",
33			want: versionedRow{
34				pkg:        "archive/tar",
35				kind:       "field",
36				structName: "Header",
37				name:       "AccessTime",
38			},
39		},
40		{
41			row: "pkg archive/tar, method (*Reader) Read([]uint8) (int, error)",
42			want: versionedRow{
43				pkg:  "archive/tar",
44				kind: "method",
45				name: "Read",
46				recv: "*Reader",
47			},
48		},
49		{
50			row: "pkg archive/zip, func FileInfoHeader(os.FileInfo) (*FileHeader, error)",
51			want: versionedRow{
52				pkg:  "archive/zip",
53				kind: "func",
54				name: "FileInfoHeader",
55			},
56		},
57		{
58			row: "pkg encoding/base32, method (Encoding) WithPadding(int32) *Encoding",
59			want: versionedRow{
60				pkg:  "encoding/base32",
61				kind: "method",
62				name: "WithPadding",
63				recv: "Encoding",
64			},
65		},
66	}
67
68	for i, tt := range tests {
69		got, ok := parseRow(tt.row)
70		if !ok {
71			got = versionedRow{}
72		}
73		if got != tt.want {
74			t.Errorf("%d. parseRow(%q) = %+v; want %+v", i, tt.row, got, tt.want)
75		}
76	}
77}
78
79// hasTag checks whether a given release tag is contained in the current version
80// of the go binary.
81func hasTag(t string) bool {
82	for _, v := range build.Default.ReleaseTags {
83		if t == v {
84			return true
85		}
86	}
87	return false
88}
89
90func TestAPIVersion(t *testing.T) {
91	av, err := parsePackageAPIInfo()
92	if err != nil {
93		t.Fatal(err)
94	}
95	for _, tc := range []struct {
96		kind     string
97		pkg      string
98		name     string
99		receiver string
100		want     string
101	}{
102		// Things that were added post-1.0 should appear
103		{"func", "archive/tar", "FileInfoHeader", "", "1.1"},
104		{"type", "bufio", "Scanner", "", "1.1"},
105		{"method", "bufio", "WriteTo", "*Reader", "1.1"},
106
107		{"func", "bytes", "LastIndexByte", "", "1.5"},
108		{"type", "crypto", "Decrypter", "", "1.5"},
109		{"method", "crypto/rsa", "Decrypt", "*PrivateKey", "1.5"},
110		{"method", "debug/dwarf", "GoString", "Class", "1.5"},
111
112		{"func", "os", "IsTimeout", "", "1.10"},
113		{"type", "strings", "Builder", "", "1.10"},
114		{"method", "strings", "WriteString", "*Builder", "1.10"},
115
116		// Things from package syscall should never appear
117		{"func", "syscall", "FchFlags", "", ""},
118		{"type", "syscall", "Inet4Pktinfo", "", ""},
119
120		// Things added in Go 1 should never appear
121		{"func", "archive/tar", "NewReader", "", ""},
122		{"type", "archive/tar", "Header", "", ""},
123		{"method", "archive/tar", "Next", "*Reader", ""},
124	} {
125		if tc.want != "" && !hasTag("go"+tc.want) {
126			continue
127		}
128		if got := av.sinceVersionFunc(tc.kind, tc.receiver, tc.name, tc.pkg); got != tc.want {
129			t.Errorf(`sinceFunc("%s", "%s", "%s", "%s") = "%s"; want "%s"`, tc.kind, tc.receiver, tc.name, tc.pkg, got, tc.want)
130		}
131	}
132}
133