1 package sourcemap_test
2
3 import (
4 "encoding/json"
5 "fmt"
6 "io/ioutil"
7 "net/http"
8 "strings"
9 "testing"
10
11 "github.com/go-sourcemap/sourcemap"
12 )
13
14 const jqSourceMapURL = "http://code.jquery.com/jquery-2.0.3.min.map"
15
16 var jqSourceMapBytes []byte
17
18 func init() {
19 resp, err := http.Get(jqSourceMapURL)
20 if err != nil {
21 panic(err)
22 }
23 defer resp.Body.Close()
24
25 jqSourceMapBytes, err = ioutil.ReadAll(resp.Body)
26 if err != nil {
27 panic(err)
28 }
29 }
30
31 type sourceMapTest struct {
32 genLine int
33 genColumn int
34 wantedSource string
35 wantedName string
36 wantedLine int
37 wantedColumn int
38 }
39
40 func (test *sourceMapTest) String() string {
41 return fmt.Sprintf("line=%d col=%d in file=%s", test.genLine, test.genColumn, test.wantedSource)
42 }
43
44 func (test *sourceMapTest) assert(t *testing.T, smap *sourcemap.Consumer) {
45 source, name, line, col, ok := smap.Source(test.genLine, test.genColumn)
46 if !ok {
47 if test.wantedSource == "" &&
48 test.wantedName == "" &&
49 test.wantedLine == 0 &&
50 test.wantedColumn == 0 {
51 return
52 }
53 t.Fatalf("Source not found for %s", test)
54 }
55 if source != test.wantedSource {
56 t.Fatalf("file: got %q, wanted %q (%s)", source, test.wantedSource, test)
57 }
58 if name != test.wantedName {
59 t.Fatalf("func: got %q, wanted %q (%s)", name, test.wantedName, test)
60 }
61 if line != test.wantedLine {
62 t.Fatalf("line: got %d, wanted %d (%s)", line, test.wantedLine, test)
63 }
64 if col != test.wantedColumn {
65 t.Fatalf("column: got %d, wanted %d (%s)", col, test.wantedColumn, test)
66 }
67 }
68
69 func TestSourceMap(t *testing.T) {
70 testSourceMap(t, sourceMapJSON)
71 }
72
73 func TestIndexedSourceMap(t *testing.T) {
74 testSourceMap(t, indexedSourceMapJSON)
75 }
76
77 func testSourceMap(t *testing.T, json string) {
78 smap, err := sourcemap.Parse("", []byte(json))
79 if err != nil {
80 t.Fatal(err)
81 }
82
83 tests := []sourceMapTest{
84 {1, 1, "/the/root/one.js", "", 1, 1},
85 {1, 5, "/the/root/one.js", "", 1, 5},
86 {1, 9, "/the/root/one.js", "", 1, 11},
87 {1, 18, "/the/root/one.js", "bar", 1, 21},
88 {1, 21, "/the/root/one.js", "", 2, 3},
89 {1, 28, "/the/root/one.js", "baz", 2, 10},
90 {1, 32, "/the/root/one.js", "bar", 2, 14},
91
92 {2, 1, "/the/root/two.js", "", 1, 1},
93 {2, 5, "/the/root/two.js", "", 1, 5},
94 {2, 9, "/the/root/two.js", "", 1, 11},
95 {2, 18, "/the/root/two.js", "n", 1, 21},
96 {2, 21, "/the/root/two.js", "", 2, 3},
97 {2, 28, "/the/root/two.js", "n", 2, 10},
98
99
100 {1, 20, "/the/root/one.js", "bar", 1, 21},
101 {1, 30, "/the/root/one.js", "baz", 2, 10},
102 {2, 12, "/the/root/two.js", "", 1, 11},
103 }
104 for i := range tests {
105 tests[i].assert(t, smap)
106 }
107
108 content := smap.SourceContent("/the/root/one.js")
109 if content != oneSourceContent {
110 t.Fatalf("%q != %q", content, oneSourceContent)
111 }
112
113 content = smap.SourceContent("/the/root/two.js")
114 if content != twoSourceContent {
115 t.Fatalf("%q != %q", content, twoSourceContent)
116 }
117
118 _, _, _, _, ok := smap.Source(3, 0)
119 if ok {
120 t.Fatal("source must not exist")
121 }
122 }
123
124 func TestSourceRootURL(t *testing.T) {
125 jsonStr := sourceMapJSON
126 jsonStr = strings.Replace(jsonStr, "/the/root", "http://the/root", 1)
127 jsonStr = strings.Replace(jsonStr, "one.js", "../one.js", 1)
128
129 smap, err := sourcemap.Parse("", []byte(jsonStr))
130 if err != nil {
131 t.Fatal(err)
132 }
133
134 tests := []*sourceMapTest{
135 {1, 1, "http://the/one.js", "", 1, 1},
136 {2, 1, "http://the/root/two.js", "", 1, 1},
137 }
138 for _, test := range tests {
139 test.assert(t, smap)
140 }
141 }
142
143 func TestEmptySourceRootURL(t *testing.T) {
144 jsonStr := sourceMapJSON
145 jsonStr = strings.Replace(jsonStr, "/the/root", "", 1)
146 jsonStr = strings.Replace(jsonStr, "one.js", "../one.js", 1)
147
148 smap, err := sourcemap.Parse("http://the/root/app.min.map", []byte(jsonStr))
149 if err != nil {
150 t.Fatal(err)
151 }
152
153 tests := []*sourceMapTest{
154 {1, 1, "http://the/one.js", "", 1, 1},
155 {2, 1, "http://the/root/two.js", "", 1, 1},
156 }
157 for _, test := range tests {
158 test.assert(t, smap)
159 }
160 }
161
162 func TestAbsSourceURL(t *testing.T) {
163 jsonStr := sourceMapJSON
164 jsonStr = strings.Replace(jsonStr, "/the/root", "", 1)
165 jsonStr = strings.Replace(jsonStr, "one.js", "http://the/root/one.js", 1)
166 jsonStr = strings.Replace(jsonStr, "two.js", "/another/root/two.js", 1)
167
168 testAbsSourceURL(t, "", jsonStr)
169 testAbsSourceURL(t, "http://path/to/map", jsonStr)
170 }
171
172 func testAbsSourceURL(t *testing.T, mapURL, jsonStr string) {
173 smap, err := sourcemap.Parse(mapURL, []byte(jsonStr))
174 if err != nil {
175 t.Fatal(err)
176 }
177
178 tests := []*sourceMapTest{
179 {1, 1, "http://the/root/one.js", "", 1, 1},
180 {2, 1, "/another/root/two.js", "", 1, 1},
181 }
182 for _, test := range tests {
183 test.assert(t, smap)
184 }
185 }
186
187 func TestJQuerySourceMap(t *testing.T) {
188 smap, err := sourcemap.Parse(jqSourceMapURL, jqSourceMapBytes)
189 if err != nil {
190 t.Fatal(err)
191 }
192
193 tests := []*sourceMapTest{
194 {1, 1, "", "", 0, 0},
195 {4, 0, "", "", 0, 0},
196 {4, 1, "http://code.jquery.com/jquery-2.0.3.js", "", 14, 0},
197 {4, 10, "http://code.jquery.com/jquery-2.0.3.js", "window", 14, 11},
198 {5, 6789, "http://code.jquery.com/jquery-2.0.3.js", "apply", 4360, 27},
199 {5, 10006, "http://code.jquery.com/jquery-2.0.3.js", "apply", 4676, 8},
200 {4, 553, "http://code.jquery.com/jquery-2.0.3.js", "ready", 93, 9},
201 {999999, 0, "", "", 0, 0},
202 }
203 for _, test := range tests {
204 test.assert(t, smap)
205 }
206 }
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230 const genCode = `exports.testGeneratedCode = "ONE.foo=function(a){return baz(a);};
231 TWO.inc=function(a){return a+1;};`
232
233 var oneSourceContent = `ONE.foo = function (bar) {
234 return baz(bar);
235 };`
236
237 var twoSourceContent = `TWO.inc = function (n) {
238 return n + 1;
239 };`
240
241 var sourceMapJSON = `{
242 "version": 3,
243 "file": "min.js",
244 "sources": ["one.js", "two.js"],
245 "sourcesContent": ` + j([]string{oneSourceContent, twoSourceContent}) + `,
246 "sourceRoot": "/the/root",
247 "names": ["bar", "baz", "n"],
248 "mappings": "CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA"
249 }`
250
251 func j(v interface{}) string {
252 b, _ := json.Marshal(v)
253 return string(b)
254 }
255
256 var indexedSourceMapJSON = `{
257 "version": 3,
258 "file": "min.js",
259 "sections": [{
260 "offset": {"line": 0, "column": 0},
261 "map": {
262 "version": 3,
263 "file": "min.js",
264 "sources": ["one.js"],
265 "sourcesContent": ` + j([]string{oneSourceContent}) + `,
266 "sourceRoot": "/the/root",
267 "names": ["bar", "baz"],
268 "mappings": "CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID"
269 }
270 }, {
271 "offset": {"line": 1, "column": 0},
272 "map": {
273 "version": 3,
274 "file": "min.js",
275 "sources": ["two.js"],
276 "sourcesContent": ` + j([]string{twoSourceContent}) + `,
277 "sourceRoot": "/the/root",
278 "names": ["n"],
279 "mappings": "CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOA"
280 }
281 }]
282 }`
283
View as plain text