1// Copyright 2017 Google Inc. All rights reserved.
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
15package jar
16
17import (
18	"bytes"
19	"io"
20	"testing"
21)
22
23func TestGetJavaPackage(t *testing.T) {
24	type args struct {
25		r   io.Reader
26		src string
27	}
28	tests := []struct {
29		name    string
30		in      string
31		want    string
32		wantErr bool
33	}{
34		{
35			name: "simple",
36			in:   "package foo.bar;",
37			want: "foo.bar",
38		},
39		{
40			name: "comment",
41			in:   "/* test */\npackage foo.bar;",
42			want: "foo.bar",
43		},
44		{
45			name: "no package",
46			in:   "import foo.bar;",
47			want: "",
48		},
49		{
50			name:    "missing semicolon error",
51			in:      "package foo.bar",
52			wantErr: true,
53		},
54		{
55			name:    "parser error",
56			in:      "/*",
57			wantErr: true,
58		},
59		{
60			name:    "parser ident error",
61			in:      "package 0foo.bar;",
62			wantErr: true,
63		},
64	}
65	for _, tt := range tests {
66		t.Run(tt.name, func(t *testing.T) {
67			buf := bytes.NewBufferString(tt.in)
68			got, err := JavaPackage(buf, "<test>")
69			if (err != nil) != tt.wantErr {
70				t.Errorf("JavaPackage() error = %v, wantErr %v", err, tt.wantErr)
71				return
72			}
73			if got != tt.want {
74				t.Errorf("JavaPackage() = %v, want %v", got, tt.want)
75			}
76		})
77	}
78}
79
80func Test_javaIdentRune(t *testing.T) {
81	// runes that should be valid anywhere in an identifier
82	validAnywhere := []rune{
83		// letters, $, _
84		'a',
85		'A',
86		'$',
87		'_',
88
89		// assorted unicode
90		'��',
91		'��',
92		'Dž',
93		'ῼ',
94		'ʰ',
95		'゚',
96		'ƻ',
97		'��',
98		'₩',
99		'_',
100		'Ⅰ',
101		'��',
102	}
103
104	// runes that should be invalid as the first rune in an identifier, but valid anywhere else
105	validAfterFirst := []rune{
106		// digits
107		'0',
108
109		// assorted unicode
110		'᥍',
111		'��',
112		'ྂ',
113		'��',
114
115		// control characters
116		'\x00',
117		'\b',
118		'\u000e',
119		'\u001b',
120		'\u007f',
121		'\u009f',
122		'\u00ad',
123		0xE007F,
124
125		// zero width space
126		'\u200b',
127	}
128
129	// runes that should never be valid in an identifier
130	invalid := []rune{
131		';',
132		0x110000,
133	}
134
135	validFirst := validAnywhere
136	invalidFirst := append(validAfterFirst, invalid...)
137	validPart := append(validAnywhere, validAfterFirst...)
138	invalidPart := invalid
139
140	check := func(t *testing.T, ch rune, i int, want bool) {
141		t.Helper()
142		if got := javaIdentRune(ch, i); got != want {
143			t.Errorf("javaIdentRune() = %v, want %v", got, want)
144		}
145	}
146
147	t.Run("first", func(t *testing.T) {
148		t.Run("valid", func(t *testing.T) {
149			for _, ch := range validFirst {
150				t.Run(string(ch), func(t *testing.T) {
151					check(t, ch, 0, true)
152				})
153			}
154		})
155
156		t.Run("invalid", func(t *testing.T) {
157			for _, ch := range invalidFirst {
158				t.Run(string(ch), func(t *testing.T) {
159					check(t, ch, 0, false)
160				})
161			}
162		})
163	})
164
165	t.Run("part", func(t *testing.T) {
166		t.Run("valid", func(t *testing.T) {
167			for _, ch := range validPart {
168				t.Run(string(ch), func(t *testing.T) {
169					check(t, ch, 1, true)
170				})
171			}
172		})
173
174		t.Run("invalid", func(t *testing.T) {
175			for _, ch := range invalidPart {
176				t.Run(string(ch), func(t *testing.T) {
177					check(t, ch, 1, false)
178				})
179			}
180		})
181	})
182}
183