1package parse
2
3import (
4	"encoding/base64"
5	"mime"
6	"testing"
7
8	"github.com/tdewolff/test"
9)
10
11func TestParseNumber(t *testing.T) {
12	var numberTests = []struct {
13		number   string
14		expected int
15	}{
16		{"5", 1},
17		{"0.51", 4},
18		{"0.5e-99", 7},
19		{"0.5e-", 3},
20		{"+50.0", 5},
21		{".0", 2},
22		{"0.", 1},
23		{"", 0},
24		{"+", 0},
25		{".", 0},
26		{"a", 0},
27	}
28	for _, tt := range numberTests {
29		t.Run(tt.number, func(t *testing.T) {
30			n := Number([]byte(tt.number))
31			test.T(t, n, tt.expected)
32		})
33	}
34}
35
36func TestParseDimension(t *testing.T) {
37	var dimensionTests = []struct {
38		dimension    string
39		expectedNum  int
40		expectedUnit int
41	}{
42		{"5px", 1, 2},
43		{"5px ", 1, 2},
44		{"5%", 1, 1},
45		{"5em", 1, 2},
46		{"px", 0, 0},
47		{"1", 1, 0},
48		{"1~", 1, 0},
49	}
50	for _, tt := range dimensionTests {
51		t.Run(tt.dimension, func(t *testing.T) {
52			num, unit := Dimension([]byte(tt.dimension))
53			test.T(t, num, tt.expectedNum, "number")
54			test.T(t, unit, tt.expectedUnit, "unit")
55		})
56	}
57}
58
59func TestMediatype(t *testing.T) {
60	var mediatypeTests = []struct {
61		mediatype        string
62		expectedMimetype string
63		expectedParams   map[string]string
64	}{
65		{"text/plain", "text/plain", nil},
66		{"text/plain;charset=US-ASCII", "text/plain", map[string]string{"charset": "US-ASCII"}},
67		{" text/plain  ; charset = US-ASCII ", "text/plain", map[string]string{"charset": "US-ASCII"}},
68		{" text/plain  a", "text/plain", nil},
69		{"text/plain;base64", "text/plain", map[string]string{"base64": ""}},
70		{"text/plain;inline=;base64", "text/plain", map[string]string{"inline": "", "base64": ""}},
71		{"ÿ   ", "ÿ ", nil}, // OSS-Fuzz; ÿ is two bytes in UTF8
72		{"ÿ  ;", "ÿ ", map[string]string{"": ""}},
73	}
74	for _, tt := range mediatypeTests {
75		t.Run(tt.mediatype, func(t *testing.T) {
76			mimetype, params := Mediatype([]byte(tt.mediatype))
77			test.String(t, string(mimetype), tt.expectedMimetype, "mimetype")
78			test.T(t, params, tt.expectedParams, "parameters") // TODO
79		})
80	}
81}
82
83func TestParseDataURI(t *testing.T) {
84	var dataURITests = []struct {
85		dataURI          string
86		expectedMimetype string
87		expectedData     string
88		expectedErr      error
89	}{
90		{"www.domain.com", "", "", ErrBadDataURI},
91		{"data:,", "text/plain", "", nil},
92		{"data:text/xml,", "text/xml", "", nil},
93		{"data:,text", "text/plain", "text", nil},
94		{"data:;base64,dGV4dA==", "text/plain", "text", nil},
95		{"data:image/svg+xml,", "image/svg+xml", "", nil},
96		{"data:;base64,()", "", "", base64.CorruptInputError(0)},
97		{"data:image/svg+xml,%3Cpath%20stroke-width='9.38%'/%3E", "image/svg+xml", "<path stroke-width='9.38%'/>", nil},
98		{"data:,%ii", "text/plain", "%ii", nil},
99	}
100	for _, tt := range dataURITests {
101		t.Run(tt.dataURI, func(t *testing.T) {
102			mimetype, data, err := DataURI([]byte(tt.dataURI))
103			test.T(t, err, tt.expectedErr)
104			test.String(t, string(mimetype), tt.expectedMimetype, "mimetype")
105			test.String(t, string(data), tt.expectedData, "data")
106		})
107	}
108}
109
110func TestParseQuoteEntity(t *testing.T) {
111	var quoteEntityTests = []struct {
112		quoteEntity   string
113		expectedQuote byte
114		expectedN     int
115	}{
116		{"&#34;", '"', 5},
117		{"&#039;", '\'', 6},
118		{"&#x0022;", '"', 8},
119		{"&#x27;", '\'', 6},
120		{"&quot;", '"', 6},
121		{"&apos;", '\'', 6},
122		{"&gt;", 0x00, 0},
123		{"&amp;", 0x00, 0},
124	}
125	for _, tt := range quoteEntityTests {
126		t.Run(tt.quoteEntity, func(t *testing.T) {
127			quote, n := QuoteEntity([]byte(tt.quoteEntity))
128			test.T(t, quote, tt.expectedQuote, "quote")
129			test.T(t, n, tt.expectedN, "quote length")
130		})
131	}
132}
133
134////////////////////////////////////////////////////////////////
135
136func BenchmarkParseMediatypeStd(b *testing.B) {
137	mediatype := "text/plain"
138	for i := 0; i < b.N; i++ {
139		mime.ParseMediaType(mediatype)
140	}
141}
142
143func BenchmarkParseMediatypeParamStd(b *testing.B) {
144	mediatype := "text/plain;inline=1"
145	for i := 0; i < b.N; i++ {
146		mime.ParseMediaType(mediatype)
147	}
148}
149
150func BenchmarkParseMediatypeParamsStd(b *testing.B) {
151	mediatype := "text/plain;charset=US-ASCII;language=US-EN;compression=gzip;base64"
152	for i := 0; i < b.N; i++ {
153		mime.ParseMediaType(mediatype)
154	}
155}
156
157func BenchmarkParseMediatypeParse(b *testing.B) {
158	mediatype := []byte("text/plain")
159	for i := 0; i < b.N; i++ {
160		Mediatype(mediatype)
161	}
162}
163
164func BenchmarkParseMediatypeParamParse(b *testing.B) {
165	mediatype := []byte("text/plain;inline=1")
166	for i := 0; i < b.N; i++ {
167		Mediatype(mediatype)
168	}
169}
170
171func BenchmarkParseMediatypeParamsParse(b *testing.B) {
172	mediatype := []byte("text/plain;charset=US-ASCII;language=US-EN;compression=gzip;base64")
173	for i := 0; i < b.N; i++ {
174		Mediatype(mediatype)
175	}
176}
177