Files
2024-02-15 17:01:50 +00:00

542 lines
16 KiB
Python

from unittest import TestCase
from symbolic.sourcemap import SourceMapTokenMatch, SourceMapView
from sentry.utils import json
sourcemap = b"""{
"version":3,
"file":"file.min.js",
"sources":["file1.js","file2.js"],
"names":["add","a","b","multiply","divide","c","e","Raven","captureException"],
"mappings":"AAAA,QAASA,KAAIC,EAAGC,GACf,YACA,OAAOD,GAAIC,ECFZ,QAASC,UAASF,EAAGC,GACpB,YACA,OAAOD,GAAIC,EAEZ,QAASE,QAAOH,EAAGC,GAClB,YACA,KACC,MAAOC,UAASH,IAAIC,EAAGC,GAAID,EAAGC,GAAKG,EAClC,MAAOC,GACRC,MAAMC,iBAAiBF",
"sourceRoot": "foo"
}"""
indexed_sourcemap_example = json.dumps(
{
"version": 3,
"file": "min.js",
"sections": [
{
"offset": {"line": 0, "column": 0},
"map": {
"version": 3,
"sources": ["one.js"],
"sourcesContent": [
" ONE.foo = function (bar) {\n" + " return baz(bar);\n" + " };"
],
"names": ["bar", "baz"],
"mappings": "CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID",
"file": "min.js",
"sourceRoot": "/the/root",
},
},
{
"offset": {"line": 1, "column": 0},
"map": {
"version": 3,
"sources": ["two.js"],
"sourcesContent": [
" TWO.inc = function (n) {\n" + " return n + 1;\n" + " };"
],
"names": ["n"],
"mappings": "CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOA",
"file": "min.js",
"sourceRoot": "/the/root",
},
},
],
}
).encode("utf-8")
class FindSourceTest(TestCase):
def test_simple(self):
smap_view = SourceMapView.from_json_bytes(sourcemap)
result = smap_view.lookup(0, 56)
assert result == SourceMapTokenMatch(
dst_line=0,
dst_col=50,
src="foo/file2.js",
src_line=0,
src_col=9,
src_id=1,
name="multiply",
)
# Start of minified file (exact match first line/col tuple)
result = smap_view.lookup(0, 0)
assert result == SourceMapTokenMatch(
dst_line=0, dst_col=0, src="foo/file1.js", src_line=0, src_col=0, src_id=0, name=None
)
# Last character in mapping
result = smap_view.lookup(0, 36)
assert result == SourceMapTokenMatch(
dst_line=0, dst_col=30, src="foo/file1.js", src_line=2, src_col=1, src_id=0, name=None
)
# First character in mapping (exact match line/col tuple)
result = smap_view.lookup(0, 37)
assert result == SourceMapTokenMatch(
dst_line=0, dst_col=37, src="foo/file1.js", src_line=2, src_col=8, src_id=0, name="a"
)
# End of minified file (character *beyond* last line/col tuple)
result = smap_view.lookup(0, 192)
assert result == SourceMapTokenMatch(
dst_line=0, dst_col=191, src="foo/file2.js", src_line=9, src_col=25, src_id=1, name="e"
)
class IterSourcesTest(TestCase):
def test_basic(self):
smap_view = SourceMapView.from_json_bytes(sourcemap)
assert list(smap_view.iter_sources()) == [(0, "foo/file1.js"), (1, "foo/file2.js")]
class GetSourceContentsTest(TestCase):
def test_no_inline(self):
# basic sourcemap fixture has no inlined sources, so expect None
smap_view = SourceMapView.from_json_bytes(sourcemap)
source = smap_view.get_sourceview(0)
assert source is None
def test_indexed_inline(self):
smap_view = SourceMapView.from_json_bytes(indexed_sourcemap_example)
sview_0 = smap_view.get_sourceview(0)
assert sview_0 is not None
assert sview_0.get_source() == (
" ONE.foo = function (bar) {\n" + " return baz(bar);\n" + " };"
)
sview_1 = smap_view.get_sourceview(1)
assert sview_1 is not None
assert sview_1.get_source() == (
" TWO.inc = function (n) {\n" + " return n + 1;\n" + " };"
)
class ParseSourcemapTest(TestCase):
def test_basic(self):
index = SourceMapView.from_json_bytes(sourcemap)
assert list(index) == [
SourceMapTokenMatch(
dst_line=0,
dst_col=0,
src="foo/file1.js",
src_line=0,
src_col=0,
src_id=0,
name=None,
),
SourceMapTokenMatch(
dst_line=0,
dst_col=8,
src="foo/file1.js",
src_line=0,
src_col=9,
src_id=0,
name="add",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=13,
src="foo/file1.js",
src_line=0,
src_col=13,
src_id=0,
name="a",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=15,
src="foo/file1.js",
src_line=0,
src_col=16,
src_id=0,
name="b",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=18,
src="foo/file1.js",
src_line=1,
src_col=1,
src_id=0,
name=None,
),
SourceMapTokenMatch(
dst_line=0,
dst_col=30,
src="foo/file1.js",
src_line=2,
src_col=1,
src_id=0,
name=None,
),
SourceMapTokenMatch(
dst_line=0,
dst_col=37,
src="foo/file1.js",
src_line=2,
src_col=8,
src_id=0,
name="a",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=40,
src="foo/file1.js",
src_line=2,
src_col=12,
src_id=0,
name="b",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=42,
src="foo/file2.js",
src_line=0,
src_col=0,
src_id=1,
name=None,
),
SourceMapTokenMatch(
dst_line=0,
dst_col=50,
src="foo/file2.js",
src_line=0,
src_col=9,
src_id=1,
name="multiply",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=60,
src="foo/file2.js",
src_line=0,
src_col=18,
src_id=1,
name="a",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=62,
src="foo/file2.js",
src_line=0,
src_col=21,
src_id=1,
name="b",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=65,
src="foo/file2.js",
src_line=1,
src_col=1,
src_id=1,
name=None,
),
SourceMapTokenMatch(
dst_line=0,
dst_col=77,
src="foo/file2.js",
src_line=2,
src_col=1,
src_id=1,
name=None,
),
SourceMapTokenMatch(
dst_line=0,
dst_col=84,
src="foo/file2.js",
src_line=2,
src_col=8,
src_id=1,
name="a",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=87,
src="foo/file2.js",
src_line=2,
src_col=12,
src_id=1,
name="b",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=89,
src="foo/file2.js",
src_line=4,
src_col=0,
src_id=1,
name=None,
),
SourceMapTokenMatch(
dst_line=0,
dst_col=97,
src="foo/file2.js",
src_line=4,
src_col=9,
src_id=1,
name="divide",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=105,
src="foo/file2.js",
src_line=4,
src_col=16,
src_id=1,
name="a",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=107,
src="foo/file2.js",
src_line=4,
src_col=19,
src_id=1,
name="b",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=110,
src="foo/file2.js",
src_line=5,
src_col=1,
src_id=1,
name=None,
),
SourceMapTokenMatch(
dst_line=0,
dst_col=122,
src="foo/file2.js",
src_line=6,
src_col=1,
src_id=1,
name=None,
),
SourceMapTokenMatch(
dst_line=0,
dst_col=127,
src="foo/file2.js",
src_line=7,
src_col=2,
src_id=1,
name=None,
),
SourceMapTokenMatch(
dst_line=0,
dst_col=133,
src="foo/file2.js",
src_line=7,
src_col=9,
src_id=1,
name="multiply",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=143,
src="foo/file2.js",
src_line=7,
src_col=18,
src_id=1,
name="add",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=147,
src="foo/file2.js",
src_line=7,
src_col=22,
src_id=1,
name="a",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=149,
src="foo/file2.js",
src_line=7,
src_col=25,
src_id=1,
name="b",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=152,
src="foo/file2.js",
src_line=7,
src_col=29,
src_id=1,
name="a",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=154,
src="foo/file2.js",
src_line=7,
src_col=32,
src_id=1,
name="b",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=157,
src="foo/file2.js",
src_line=7,
src_col=37,
src_id=1,
name="c",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=159,
src="foo/file2.js",
src_line=8,
src_col=3,
src_id=1,
name=None,
),
SourceMapTokenMatch(
dst_line=0,
dst_col=165,
src="foo/file2.js",
src_line=8,
src_col=10,
src_id=1,
name="e",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=168,
src="foo/file2.js",
src_line=9,
src_col=2,
src_id=1,
name="Raven",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=174,
src="foo/file2.js",
src_line=9,
src_col=8,
src_id=1,
name="captureException",
),
SourceMapTokenMatch(
dst_line=0,
dst_col=191,
src="foo/file2.js",
src_line=9,
src_col=25,
src_id=1,
name="e",
),
]
class ParseIndexedSourcemapTest(TestCase):
# Tests lookups that fall exactly on source map token boundaries
# https://github.com/mozilla/source-map/blob/master/test/test-source-map-consumer.js#138
def test_exact_mappings(self):
smap_view = SourceMapView.from_json_bytes(indexed_sourcemap_example)
# one.js
assert smap_view.lookup(0, 1) == SourceMapTokenMatch(
dst_line=0,
dst_col=1,
src="/the/root/one.js",
src_line=0,
src_col=1,
src_id=0,
name=None,
)
assert smap_view.lookup(0, 18) == SourceMapTokenMatch(
dst_line=0,
dst_col=18,
src="/the/root/one.js",
src_line=0,
src_col=21,
src_id=0,
name="bar",
)
assert smap_view.lookup(0, 28) == SourceMapTokenMatch(
dst_line=0,
dst_col=28,
src="/the/root/one.js",
src_line=1,
src_col=10,
src_id=0,
name="baz",
)
# two.js
assert smap_view.lookup(1, 18) == SourceMapTokenMatch(
dst_line=1,
dst_col=18,
src="/the/root/two.js",
src_line=0,
src_col=21,
src_id=1,
name="n",
)
assert smap_view.lookup(1, 21) == SourceMapTokenMatch(
dst_line=1,
dst_col=21,
src="/the/root/two.js",
src_line=1,
src_col=3,
src_id=1,
name=None,
)
assert smap_view.lookup(1, 21) == SourceMapTokenMatch(
dst_line=1,
dst_col=21,
src="/the/root/two.js",
src_line=1,
src_col=3,
src_id=1,
name=None,
)
# Tests lookups that fall inside source map token boundaries
# https://github.com/mozilla/source-map/blob/master/test/test-source-map-consumer.js#181
def test_fuzzy_mapping(self):
smap_view = SourceMapView.from_json_bytes(indexed_sourcemap_example)
# one.js
assert smap_view.lookup(0, 20) == SourceMapTokenMatch(
dst_line=0,
dst_col=18,
src="/the/root/one.js",
src_line=0,
src_col=21,
src_id=0,
name="bar",
)
assert smap_view.lookup(0, 30) == SourceMapTokenMatch(
dst_line=0,
dst_col=28,
src="/the/root/one.js",
src_line=1,
src_col=10,
src_id=0,
name="baz",
)
assert smap_view.lookup(1, 12) == SourceMapTokenMatch(
dst_line=1,
dst_col=9,
src="/the/root/two.js",
src_line=0,
src_col=11,
src_id=1,
name=None,
)