use proguard::{ProguardCache, ProguardMapper, ProguardMapping, StackFrame};
#[test]
fn test_remap() {
let mapper = ProguardMapper::from(
r#"some.Class -> obfuscated:
7:8:void method3(long):78:79 -> main
7:8:void method2(int):87 -> main
7:8:void method1(java.lang.String):95 -> main
7:8:void main(java.lang.String[]):101 -> main"#,
);
let stacktrace = " at obfuscated.main(Foo.java:8)";
let mapped = mapper.remap_stacktrace(stacktrace).unwrap();
assert_eq!(
mapped,
" at some.Class.method3(Class.java:79)
at some.Class.method2(Class.java:87)
at some.Class.method1(Class.java:95)
at some.Class.main(Class.java:101)\n"
);
let mapper = ProguardMapper::from(
r#"com.exmaple.app.MainActivity -> com.exmaple.app.MainActivity:
com.example1.domain.MyBean myBean -> p
1:1:void <init>():11:11 -> <init>
1:1:void buttonClicked(android.view.View):29:29 -> buttonClicked
2:2:void com.example1.domain.MyBean.doWork():16:16 -> buttonClicked
2:2:void buttonClicked(android.view.View):29 -> buttonClicked
1:1:void onCreate(android.os.Bundle):17:17 -> onCreate
2:5:void onCreate(android.os.Bundle):22:25 -> onCreate"#,
);
let stacktrace = " at com.exmaple.app.MainActivity.buttonClicked(MainActivity.java:2)";
let mapped = mapper.remap_stacktrace(stacktrace).unwrap();
assert_eq!(
mapped,
" at com.example1.domain.MyBean.doWork(MyBean.java:16)
at com.exmaple.app.MainActivity.buttonClicked(MainActivity.java:29)\n"
);
let mapper = ProguardMapper::from(
r#"com.exmaple.app.MainActivity -> com.exmaple.app.MainActivity:
com.example1.domain.MyBean myBean -> k
11:11:void <init>() -> <init>
17:26:void onCreate(android.os.Bundle) -> onCreate
29:30:void buttonClicked(android.view.View) -> buttonClicked
1016:1016:void com.example1.domain.MyBean.doWork():16:16 -> buttonClicked
1016:1016:void buttonClicked(android.view.View):29 -> buttonClicked"#,
);
let stacktrace = " at com.exmaple.app.MainActivity.buttonClicked(MainActivity.java:1016)";
let mapped = mapper.remap_stacktrace(stacktrace).unwrap();
assert_eq!(
mapped,
" at com.example1.domain.MyBean.doWork(MyBean.java:16)
at com.exmaple.app.MainActivity.buttonClicked(MainActivity.java:29)\n"
);
}
#[test]
fn test_remap_no_lines() {
let mapper = ProguardMapper::from(
r#"original.class.name -> a:
void originalMethodName() -> b"#,
);
let mapped = mapper.remap_class("a");
assert_eq!(mapped, Some("original.class.name"));
let mut mapped = mapper.remap_frame(&StackFrame::new("a", "b", 10));
assert_eq!(
mapped.next().unwrap(),
StackFrame::with_file("original.class.name", "originalMethodName", 10, "name.java")
);
assert_eq!(mapped.next(), None);
}
#[test]
fn test_remap_kotlin() {
let mapper = ProguardMapper::from(
r#"io.sentry.sample.-$$Lambda$r3Avcbztes2hicEObh02jjhQqd4 -> e.a.c.a:
io.sentry.sample.MainActivity f$0 -> b
1:1:void io.sentry.sample.KotlinSampleKt.fun3(io.sentry.sample.KotlinSample):16:16 -> onClick
1:1:void io.sentry.sample.KotlinSample.fun2():11 -> onClick
1:1:void io.sentry.sample.KotlinSample.fun1():7 -> onClick
1:1:void io.sentry.sample.MainActivity.bar():56 -> onClick
1:1:void io.sentry.sample.MainActivity.foo():44 -> onClick
1:1:void io.sentry.sample.MainActivity.onClickHandler(android.view.View):40 -> onClick
1:1:void onClick(android.view.View):0 -> onClick"#,
);
let mapped = mapper
.remap_stacktrace(" at e.a.c.a.onClick(lambda:1)")
.unwrap();
assert_eq!(
mapped.trim(),
r#"at io.sentry.sample.KotlinSampleKt.fun3(KotlinSample.kt:16)
at io.sentry.sample.KotlinSample.fun2(KotlinSample.java:11)
at io.sentry.sample.KotlinSample.fun1(KotlinSample.java:7)
at io.sentry.sample.MainActivity.bar(MainActivity.java:56)
at io.sentry.sample.MainActivity.foo(MainActivity.java:44)
at io.sentry.sample.MainActivity.onClickHandler(MainActivity.java:40)
at io.sentry.sample.-$$Lambda$r3Avcbztes2hicEObh02jjhQqd4.onClick(-.java:0)"#
.trim()
);
}
#[test]
fn test_remap_just_method() {
let mapper = ProguardMapper::from(
r#"com.exmaple.app.MainActivity -> a.b.c.d:
com.example1.domain.MyBean myBean -> p
1:1:void <init>():11:11 -> <init>
1:1:void buttonClicked(android.view.View):29:29 -> buttonClicked
2:2:void com.example1.domain.MyBean.doWork():16:16 -> buttonClicked
2:2:void buttonClicked(android.view.View):29 -> buttonClicked
1:1:void onCreate(android.os.Bundle):17:17 -> onCreate
2:5:void onCreate(android.os.Bundle):22:25 -> onCreate"#,
);
let unambiguous = mapper.remap_method("a.b.c.d", "onCreate");
assert_eq!(
unambiguous,
Some(("com.exmaple.app.MainActivity", "onCreate"))
);
let ambiguous = mapper.remap_method("a.b.c.d", "buttonClicked");
assert_eq!(ambiguous, None);
}
#[test]
fn test_remap_compose_stacktrace_group_keys() {
let mapping = r#"ComposeStackTrace -> $$compose:
1:1:androidx.compose.runtime.State androidx.compose.animation.core.AnimateAsStateKt.animateFloatAsState(float,androidx.compose.animation.core.AnimationSpec,float,java.lang.String,kotlin.jvm.functions.Function1,androidx.compose.runtime.Composer,int,int):71:71 -> m$1125598679
1:1:androidx.compose.runtime.State androidx.compose.animation.core.AnimateAsStateKt.animateFloatAsState(float,androidx.compose.animation.core.AnimationSpec,float,java.lang.String,kotlin.jvm.functions.Function1,androidx.compose.runtime.Composer,int,int):73:73 -> m$1125708605"#;
let mapper = ProguardMapper::from(mapping);
let mapped = mapper
.remap_stacktrace(
r#"androidx.compose.runtime.ComposeTraceException:
at $$compose.m$1125598679(SourceFile:1)
at $$compose.m$1125708605(SourceFile:1)"#,
)
.unwrap();
assert_eq!(
mapped.trim(),
r#"androidx.compose.runtime.ComposeTraceException:
at androidx.compose.animation.core.AnimateAsStateKt.animateFloatAsState(AnimateAsState.kt:71)
at androidx.compose.animation.core.AnimateAsStateKt.animateFloatAsState(AnimateAsState.kt:73)"#
.trim()
);
}
#[test]
fn test_remap_compose_stacktrace_group_keys_cache() {
let mapping = ProguardMapping::new(
br#"ComposeStackTrace -> $$compose:
1:1:androidx.compose.runtime.State androidx.compose.animation.core.AnimateAsStateKt.animateFloatAsState(float,androidx.compose.animation.core.AnimationSpec,float,java.lang.String,kotlin.jvm.functions.Function1,androidx.compose.runtime.Composer,int,int):71:71 -> m$1125598679
1:1:androidx.compose.runtime.State androidx.compose.animation.core.AnimateAsStateKt.animateFloatAsState(float,androidx.compose.animation.core.AnimationSpec,float,java.lang.String,kotlin.jvm.functions.Function1,androidx.compose.runtime.Composer,int,int):73:73 -> m$1125708605"#,
);
let mut buf = Vec::new();
ProguardCache::write(&mapping, &mut buf).unwrap();
let cache = ProguardCache::parse(&buf).unwrap();
let mapped = cache
.remap_stacktrace(
r#"androidx.compose.runtime.ComposeTraceException:
at $$compose.m$1125598679(SourceFile:1)
at $$compose.m$1125708605(SourceFile:1)"#,
)
.unwrap();
assert_eq!(
mapped.trim(),
r#"androidx.compose.runtime.ComposeTraceException:
at androidx.compose.animation.core.AnimateAsStateKt.animateFloatAsState(AnimateAsState.kt:71)
at androidx.compose.animation.core.AnimateAsStateKt.animateFloatAsState(AnimateAsState.kt:73)"#
.trim()
);
}