common_test.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. package minify // import "github.com/tdewolff/minify"
  2. import (
  3. "fmt"
  4. "io"
  5. "io/ioutil"
  6. "math"
  7. "math/rand"
  8. "strconv"
  9. "testing"
  10. "github.com/tdewolff/test"
  11. )
  12. func TestMediatype(t *testing.T) {
  13. mediatypeTests := []struct {
  14. mediatype string
  15. expected string
  16. }{
  17. {"text/html", "text/html"},
  18. {"text/html; charset=UTF-8", "text/html;charset=utf-8"},
  19. {"text/html; charset=UTF-8 ; param = \" ; \"", "text/html;charset=utf-8;param=\" ; \""},
  20. {"text/html, text/css", "text/html,text/css"},
  21. }
  22. for _, tt := range mediatypeTests {
  23. t.Run(tt.mediatype, func(t *testing.T) {
  24. mediatype := Mediatype([]byte(tt.mediatype))
  25. test.Minify(t, tt.mediatype, nil, string(mediatype), tt.expected)
  26. })
  27. }
  28. }
  29. func TestDataURI(t *testing.T) {
  30. dataURITests := []struct {
  31. dataURI string
  32. expected string
  33. }{
  34. {"data:,text", "data:,text"},
  35. {"data:text/plain;charset=us-ascii,text", "data:,text"},
  36. {"data:TEXT/PLAIN;CHARSET=US-ASCII,text", "data:,text"},
  37. {"data:text/plain;charset=us-asciiz,text", "data:;charset=us-asciiz,text"},
  38. {"data:;base64,dGV4dA==", "data:,text"},
  39. {"data:text/svg+xml;base64,PT09PT09", "data:text/svg+xml;base64,PT09PT09"},
  40. {"data:text/xml;version=2.0,content", "data:text/xml;version=2.0,content"},
  41. {"data:text/xml; version = 2.0,content", "data:text/xml;version=2.0,content"},
  42. {"data:,=====", "data:,%3D%3D%3D%3D%3D"},
  43. {"data:,======", "data:;base64,PT09PT09"},
  44. {"data:text/x,<?x?>", "data:text/x,%3C%3Fx%3F%3E"},
  45. }
  46. m := New()
  47. m.AddFunc("text/x", func(_ *M, w io.Writer, r io.Reader, _ map[string]string) error {
  48. b, _ := ioutil.ReadAll(r)
  49. test.String(t, string(b), "<?x?>")
  50. w.Write(b)
  51. return nil
  52. })
  53. for _, tt := range dataURITests {
  54. t.Run(tt.dataURI, func(t *testing.T) {
  55. dataURI := DataURI(m, []byte(tt.dataURI))
  56. test.Minify(t, tt.dataURI, nil, string(dataURI), tt.expected)
  57. })
  58. }
  59. }
  60. func TestDecimal(t *testing.T) {
  61. numberTests := []struct {
  62. number string
  63. expected string
  64. }{
  65. {"0", "0"},
  66. {".0", "0"},
  67. {"1.0", "1"},
  68. {"0.1", ".1"},
  69. {"+1", "1"},
  70. {"-1", "-1"},
  71. {"-0.1", "-.1"},
  72. {"10", "10"},
  73. {"100", "100"},
  74. {"1000", "1000"},
  75. {"0.001", ".001"},
  76. {"0.0001", ".0001"},
  77. {"0.252", ".252"},
  78. {"1.252", "1.252"},
  79. {"-1.252", "-1.252"},
  80. {"0.075", ".075"},
  81. {"789012345678901234567890123456789e9234567890123456789", "789012345678901234567890123456789e9234567890123456789"},
  82. {".000100009", ".000100009"},
  83. {".0001000009", ".0001000009"},
  84. {".0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009", ".0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009"},
  85. {"E\x1f", "E\x1f"}, // fuzz
  86. }
  87. for _, tt := range numberTests {
  88. t.Run(tt.number, func(t *testing.T) {
  89. number := Decimal([]byte(tt.number), -1)
  90. test.Minify(t, tt.number, nil, string(number), tt.expected)
  91. })
  92. }
  93. }
  94. func TestDecimalTruncate(t *testing.T) {
  95. numberTests := []struct {
  96. number string
  97. truncate int
  98. expected string
  99. }{
  100. {"0.1", 1, ".1"},
  101. {"0.0001", 1, "0"},
  102. {"0.111", 1, ".1"},
  103. {"0.111", 0, "0"},
  104. {"0.075", 1, ".1"},
  105. {"0.025", 1, "0"},
  106. {"9.99", 1, "10"},
  107. {"8.88", 1, "8.9"},
  108. {"8.88", 0, "9"},
  109. {"8.00", 0, "8"},
  110. {".88", 0, "1"},
  111. {"1.234", 1, "1.2"},
  112. {"33.33", 0, "33"},
  113. {"29.666", 0, "30"},
  114. {"1.51", 1, "1.5"},
  115. {"1.01", 1, "1"},
  116. }
  117. for _, tt := range numberTests {
  118. t.Run(tt.number, func(t *testing.T) {
  119. number := Decimal([]byte(tt.number), tt.truncate)
  120. test.Minify(t, tt.number, nil, string(number), tt.expected, "truncate to", tt.truncate)
  121. })
  122. }
  123. }
  124. func TestNumber(t *testing.T) {
  125. numberTests := []struct {
  126. number string
  127. expected string
  128. }{
  129. {"0", "0"},
  130. {".0", "0"},
  131. {"1.0", "1"},
  132. {"0.1", ".1"},
  133. {"+1", "1"},
  134. {"-1", "-1"},
  135. {"-0.1", "-.1"},
  136. {"10", "10"},
  137. {"100", "100"},
  138. {"1000", "1e3"},
  139. {"0.001", ".001"},
  140. {"0.0001", "1e-4"},
  141. {"100e1", "1e3"},
  142. {"1.1e+1", "11"},
  143. {"1.1e6", "11e5"},
  144. {"1.1e", "1.1e"}, // broken number, don't parse
  145. {"1.1e+", "1.1e+"}, // broken number, don't parse
  146. {"0.252", ".252"},
  147. {"1.252", "1.252"},
  148. {"-1.252", "-1.252"},
  149. {"0.075", ".075"},
  150. {"789012345678901234567890123456789e9234567890123456789", "789012345678901234567890123456789e9234567890123456789"},
  151. {".000100009", "100009e-9"},
  152. {".0001000009", ".0001000009"},
  153. {".0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009", ".0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009"},
  154. {".6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e-9", ".6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e-9"},
  155. {"E\x1f", "E\x1f"}, // fuzz
  156. {"1e9223372036854775807", "1e9223372036854775807"},
  157. {"11e9223372036854775807", "11e9223372036854775807"},
  158. {".01e-9223372036854775808", ".01e-9223372036854775808"},
  159. {".011e-9223372036854775808", ".011e-9223372036854775808"},
  160. {".12345e8", "12345e3"},
  161. {".12345e7", "1234500"},
  162. {".12345e6", "123450"},
  163. {".12345e5", "12345"},
  164. {".012345e6", "12345"},
  165. {".12345e4", "1234.5"},
  166. {"-.12345e4", "-1234.5"},
  167. {".12345e0", ".12345"},
  168. {".12345e-1", ".012345"},
  169. {".12345e-2", ".0012345"},
  170. {".12345e-3", "12345e-8"},
  171. {".12345e-4", "12345e-9"},
  172. {".12345e-5", ".12345e-5"},
  173. {".123456e-3", "123456e-9"},
  174. {".123456e-2", ".00123456"},
  175. {".1234567e-4", ".1234567e-4"},
  176. {".1234567e-3", ".0001234567"},
  177. {"12345678e-1", "1234567.8"},
  178. {"72.e-3", ".072"},
  179. {"7640e-2", "76.4"},
  180. {"10.e-3", ".01"},
  181. {".0319e3", "31.9"},
  182. {"39.7e-2", ".397"},
  183. {"39.7e-3", ".0397"},
  184. {".01e1", ".1"},
  185. {".001e1", ".01"},
  186. {"39.7e-5", "397e-6"},
  187. }
  188. for _, tt := range numberTests {
  189. t.Run(tt.number, func(t *testing.T) {
  190. number := Number([]byte(tt.number), -1)
  191. test.Minify(t, tt.number, nil, string(number), tt.expected)
  192. })
  193. }
  194. }
  195. func TestNumberTruncate(t *testing.T) {
  196. numberTests := []struct {
  197. number string
  198. truncate int
  199. expected string
  200. }{
  201. {"0.1", 1, ".1"},
  202. {"0.0001", 1, "1e-4"},
  203. {"0.111", 1, ".1"},
  204. {"0.111", 0, "0"},
  205. {"0.075", 1, ".1"},
  206. {"0.025", 1, "0"},
  207. {"9.99", 1, "10"},
  208. {"8.88", 1, "8.9"},
  209. {"8.88", 0, "9"},
  210. {"8.00", 0, "8"},
  211. {".88", 0, "1"},
  212. {"1.234", 1, "1.2"},
  213. {"33.33", 0, "33"},
  214. {"29.666", 0, "30"},
  215. {"1.51", 1, "1.5"},
  216. {"1.01", 1, "1"},
  217. }
  218. for _, tt := range numberTests {
  219. t.Run(tt.number, func(t *testing.T) {
  220. number := Number([]byte(tt.number), tt.truncate)
  221. test.Minify(t, tt.number, nil, string(number), tt.expected, "truncate to", tt.truncate)
  222. })
  223. }
  224. }
  225. func TestDecimalRandom(t *testing.T) {
  226. N := int(1e4)
  227. if testing.Short() {
  228. N = 0
  229. }
  230. for i := 0; i < N; i++ {
  231. b := RandNumBytes(false)
  232. f, _ := strconv.ParseFloat(string(b), 64)
  233. b2 := make([]byte, len(b))
  234. copy(b2, b)
  235. b2 = Decimal(b2, -1)
  236. f2, _ := strconv.ParseFloat(string(b2), 64)
  237. if math.Abs(f-f2) > 1e-6 {
  238. fmt.Println("Bad:", f, "!=", f2, "in", string(b), "to", string(b2))
  239. }
  240. }
  241. }
  242. func TestNumberRandom(t *testing.T) {
  243. N := int(1e4)
  244. if testing.Short() {
  245. N = 0
  246. }
  247. for i := 0; i < N; i++ {
  248. b := RandNumBytes(true)
  249. f, _ := strconv.ParseFloat(string(b), 64)
  250. b2 := make([]byte, len(b))
  251. copy(b2, b)
  252. b2 = Number(b2, -1)
  253. f2, _ := strconv.ParseFloat(string(b2), 64)
  254. if math.Abs(f-f2) > 1e-6 {
  255. fmt.Println("Bad:", f, "!=", f2, "in", string(b), "to", string(b2))
  256. }
  257. }
  258. }
  259. ////////////////
  260. var n = 100
  261. var numbers [][]byte
  262. func TestMain(t *testing.T) {
  263. numbers = make([][]byte, 0, n)
  264. for j := 0; j < n; j++ {
  265. numbers = append(numbers, RandNumBytes(true))
  266. }
  267. }
  268. func RandNumBytes(withExp bool) []byte {
  269. var b []byte
  270. n := rand.Int() % 10
  271. for i := 0; i < n; i++ {
  272. b = append(b, byte(rand.Int()%10)+'0')
  273. }
  274. if rand.Int()%2 == 0 {
  275. b = append(b, '.')
  276. n = rand.Int() % 10
  277. for i := 0; i < n; i++ {
  278. b = append(b, byte(rand.Int()%10)+'0')
  279. }
  280. }
  281. if withExp && rand.Int()%2 == 0 {
  282. b = append(b, 'e')
  283. if rand.Int()%2 == 0 {
  284. b = append(b, '-')
  285. }
  286. n = 1 + rand.Int()%4
  287. for i := 0; i < n; i++ {
  288. b = append(b, byte(rand.Int()%10)+'0')
  289. }
  290. }
  291. return b
  292. }
  293. func BenchmarkNumber(b *testing.B) {
  294. for i := 0; i < b.N; i++ {
  295. for j := 0; j < n; j++ {
  296. Number(numbers[j], -1)
  297. }
  298. }
  299. }
  300. func BenchmarkNumber2(b *testing.B) {
  301. num := []byte("1.2345e-6")
  302. for i := 0; i < b.N; i++ {
  303. Number(num, -1)
  304. }
  305. }