-
Notifications
You must be signed in to change notification settings - Fork 45
Fix Logcat Parsing #133
Fix Logcat Parsing #133
Conversation
} | ||
|
||
// Implicitly expecting to see logs from `android.support.test.internal.runner.listener.LogRunListener`. | ||
// Was not able to find more reliable solution to capture logcat per test. | ||
val startedTest: Pair<String, String>? = newline.parseTestClassAndName("TestRunner: started: ") | ||
val finishedTest: Pair<String, String>? = newline.parseTestClassAndName("TestRunner: finished: ") | ||
val startedTest: Pair<String, String>? = newline.parseTestClassAndName("""(.*TestRunner.*: started: )(.*)\((.*)\)""".toRegex()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any chance to solve it without Regex?
My main concern is performance and readability :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wondered about perf, but personally find it very readable. It's easy to see the capture groups and destructuring makes it clear exactly what were pulling out of the log line.
I can give a non-regex implementation a shot too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's not hard, please try, would love to compare!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'd compare it with non-regex solution, too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about:
fun String.parseTestClassAndName(): Pair<String, String>? {
val tokens = split(':')
if (tokens.size != 3) return null
if (tokens[0].trimStart('I', '/').startsWith("TestRunner")) {
if (tokens[1] == " started" || tokens[1] == " finished") {
return tokens[2].substringAfter("(").removeSuffix(")") to tokens[2].substringBefore("(").trim()
}
}
return null
}
I'm not sure about the performance of split()
. Since it's a single character I'm assuming it's O(n) where n is the length of the string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the first check should be
if (!trimStart('I', '/').startsWith("TestRunner"))
so we can avoid O(n) on every log.
fun String.parseTestClassAndName(): Pair<String, String>? {
if (!trimStart('I', '/').startsWith("TestRunner")) return null
val tokens = split(':')
if (tokens.size != 3) return null
if (tokens[1] == " started" || tokens[1] == " finished") {
return tokens[2].substringAfter("(").removeSuffix(")") to tokens[2].substringBefore("(").trim()
}
return null
}
else -> it.substringAfter("(").removeSuffix(")") to it.substringBefore("(") | ||
} | ||
fun String.parseTestClassAndName(regex: Regex): Pair<String, String>? { | ||
return regex.find(this)?.destructured?.let { (_, testMethod, testClass) -> Pair(testMethod, testClass) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, typically to improve performance you create Pattern
by Pattern.compile("…")
once and use that
Btw, looks like you're committing with wrong git config, your commit doesn't have your avatar You can check if commit email matches expected that is attached to github account: git log And if it's not, fix it like that: git config user.email "[email protected]"
git commit -a --amend --reset-author |
Ah, also please add test case(s) that show how old parsing failed and new one fixes that problem! Thanks :) |
@artem-zinnatullin Please have another look. I optimized and added some tests. |
@@ -181,7 +181,21 @@ private fun pullTestFiles(adbDevice: AdbDevice, test: InstrumentationTest, outpu | |||
) | |||
} | |||
|
|||
private fun saveLogcat(adbDevice: AdbDevice, logsDir: File): Observable<Pair<String, String>> = Observable | |||
class LogLineParser { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need class :)
As you can see, Composer is class-less other than data-classes, just drop a private top-level function :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't test it if it's private.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point
|
||
context("parse test class and name") { | ||
|
||
it("parses old TestRunner start logs") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe give better name? "old" doesn't really explain what is old and what is new
Also, you can extract subject under test which is a log line that you parse into a separate variable for better test structure
val tokens = logLine.split(':') | ||
if (tokens.size != 3) return null | ||
|
||
if (tokens[1] == " started" || tokens[1] == " finished") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks vulnerable to spaces, maybe trim?
@@ -181,7 +181,21 @@ private fun pullTestFiles(adbDevice: AdbDevice, test: InstrumentationTest, outpu | |||
) | |||
} | |||
|
|||
private fun saveLogcat(adbDevice: AdbDevice, logsDir: File): Observable<Pair<String, String>> = Observable | |||
class LogLineParser { | |||
fun parseTestClassAndName(logLine: String): Pair<String, String>? { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I honestly like this non-regexp version better, much more understandable!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a bug, I forgot the "newer" logs have a ton of stuff before "TestRunner". I'll submit an update later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, so far it looks really good, keep it up 👍
bump |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work!
} | ||
|
||
it("extracts test class and method") { | ||
assertThat(args).isEqualTo(Pair("com.example.SampleClass", "someTestMethod")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: you can use infix function to create pair, it'll be little bit shorter
"com.example.SampleClass" to "someTestMethod"
import org.jetbrains.spek.api.dsl.context | ||
import org.jetbrains.spek.api.dsl.it | ||
|
||
class LogLineParserSpec : Spek({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great!
Just in case, I believe when GitHub will "Squash and Merge" it'll use first commit as base and might not associate it with your GitHub account, but I'm not sure Possible solution: rebase with |
ce4d929
to
389e31b
Compare
Fixed. Thanks @artem-zinnatullin |
@yunikkk can you PTAL and merge? :) |
Please, merge!) |
@evgengal I just built a jar and deployed that so I wouldn't have to wait. Put a fix for screenshots not working in there too, but it's kind of a special case. |
@christopherperry merged and released 0.3.3 with it, thanks! |
Well...now it doesn't work on emulators...
|
I just created a new issue for what @CristianGM is commenting, in case you'd like to treat it as a different issue: #151 |
@CristianGM @Sloy thanks for reporting, adding fix. |
Fix for #129
Might need more testing.