-
Notifications
You must be signed in to change notification settings - Fork 223
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
telemetry(amazonq): Add metrics utility to instrument generated patch…
…es applied to existing code.
- Loading branch information
C Tidd
committed
Nov 15, 2024
1 parent
e225cdc
commit 81dd90e
Showing
2 changed files
with
201 additions
and
0 deletions.
There are no files selected for viewing
73 changes: 73 additions & 0 deletions
73
...munity/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/util/DiffMetrics.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util | ||
|
||
import com.intellij.diff.comparison.ComparisonManager | ||
import com.intellij.diff.comparison.ComparisonPolicy | ||
import com.intellij.diff.fragments.LineFragment | ||
import com.intellij.openapi.progress.EmptyProgressIndicator | ||
|
||
data class DiffMetrics( | ||
val insertedLines: Int, | ||
val insertedCharacters: Int | ||
) | ||
|
||
fun lineEnding(content: String, curr: Int, end: Int): Int { | ||
require (curr <= end) { "curr must be within end of range" } | ||
require (end <= content.length) { "end must be within content" } | ||
|
||
return if (curr == end) { | ||
-1 | ||
} else if (content[curr] == '\r') { | ||
if ((curr + 1 < end) && (content[curr + 1] == '\n')) { | ||
2 | ||
} else { | ||
1 | ||
} | ||
} else if (content[curr] == '\n') { | ||
1 | ||
} else { | ||
-1 | ||
} | ||
} | ||
|
||
fun getDiffMetrics(before: String, after: String): DiffMetrics { | ||
val comparisonManager = ComparisonManager.getInstance() | ||
val fragments = comparisonManager.compareLines( | ||
before, | ||
after, | ||
ComparisonPolicy.DEFAULT, | ||
EmptyProgressIndicator() | ||
) | ||
|
||
var accLineCount = 0 | ||
var accCharCount = 0 | ||
|
||
fragments.forEach { fragment: LineFragment -> | ||
var curr = fragment.startOffset2 | ||
val end = fragment.endOffset2 | ||
|
||
while (curr < end) { | ||
accLineCount += 1 | ||
|
||
// Consume leading whitespace: | ||
while (curr < end && lineEnding(after, curr, end) == -1 && after[curr].isWhitespace()) curr++ | ||
|
||
// Consume through EOL: | ||
val lineContentStart = curr | ||
while (curr < end && lineEnding(after, curr, end) == -1) curr++ | ||
var lineContentEnd = curr | ||
curr += maxOf(lineEnding(after, curr, end), 0) | ||
|
||
// Walk back trailing whitespace and record character count before continuing to next line: | ||
while (lineContentEnd > lineContentStart && after[lineContentEnd - 1].isWhitespace()) lineContentEnd-- | ||
accCharCount += lineContentEnd - lineContentStart | ||
} | ||
} | ||
|
||
return DiffMetrics( | ||
insertedLines = accLineCount, | ||
insertedCharacters = accCharCount, | ||
) | ||
} |
128 changes: 128 additions & 0 deletions
128
...ty/tst/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/util/DiffMetricsTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util | ||
|
||
import com.intellij.testFramework.LightPlatformTestCase | ||
import com.intellij.testFramework.TestApplicationManager | ||
import kotlin.test.assertNotEquals | ||
|
||
class DiffMetricsTest : LightPlatformTestCase() { | ||
override fun setUp() { | ||
super.setUp() | ||
TestApplicationManager.getInstance() | ||
} | ||
|
||
fun `test empty input`() { | ||
val metrics = getDiffMetrics("", "") | ||
assertEquals(0, metrics.insertedLines) | ||
assertEquals(0, metrics.insertedCharacters) | ||
} | ||
|
||
fun `test insertions are counted`() { | ||
val before = """ | ||
line1 | ||
line2 | ||
""".trimIndent() | ||
|
||
val after = """ | ||
line1 | ||
inserted | ||
line2 | ||
""".trimIndent() | ||
|
||
val metrics = getDiffMetrics(before, after) | ||
assertEquals(1, metrics.insertedLines) | ||
assertEquals(8, metrics.insertedCharacters) | ||
} | ||
|
||
fun `test modifications are counted`() { | ||
val before = """ | ||
line1 | ||
line2 | ||
line3 | ||
""".trimIndent() | ||
|
||
val after = """ | ||
line1 | ||
modified | ||
line3 | ||
""".trimIndent() | ||
|
||
val metrics = getDiffMetrics(before, after) | ||
assertEquals(1, metrics.insertedLines) | ||
assertEquals(8, metrics.insertedCharacters) | ||
} | ||
|
||
fun `test deletions are counted`() { | ||
val before = """ | ||
line1 | ||
line2 | ||
line3 | ||
""".trimIndent() | ||
|
||
val after = """ | ||
line1 | ||
line3 | ||
""".trimIndent() | ||
|
||
val metrics = getDiffMetrics(before, after) | ||
assertEquals(0, metrics.insertedLines) | ||
assertEquals(0, metrics.insertedCharacters) | ||
} | ||
|
||
fun `test multiline and multiple hunks are counted`() { | ||
val before = """ | ||
line1 | ||
line2 | ||
line3 | ||
""".trimIndent() | ||
|
||
val after = """ | ||
inserted1 | ||
line1 | ||
inserted2 | ||
inserted3 | ||
line3 | ||
inserted4 | ||
""".trimIndent() | ||
|
||
val metrics = getDiffMetrics(before, after) | ||
assertEquals(4, metrics.insertedLines) | ||
assertEquals(36, metrics.insertedCharacters) | ||
} | ||
|
||
fun `test empty lines are counted`() { | ||
val before = "line1" | ||
val after = "line1\n\nline2" | ||
val metrics = getDiffMetrics(before, after) | ||
assertEquals(2, metrics.insertedLines) | ||
assertEquals(5, metrics.insertedCharacters) | ||
} | ||
|
||
fun `test trailing newline is not counted`() { | ||
val before = "line1" | ||
val after = "line1\nline2\n" | ||
val metrics = getDiffMetrics(before, after) | ||
assertEquals(1, metrics.insertedLines) | ||
assertEquals(5, metrics.insertedCharacters) | ||
} | ||
|
||
fun `test newline sequences are counted`() { | ||
val before = "line1" | ||
val after = "line1\nline2\rline3\r\nline4" | ||
val metrics = getDiffMetrics(before, after) | ||
assertEquals(3, metrics.insertedLines) | ||
assertEquals(15, metrics.insertedCharacters) | ||
} | ||
|
||
fun `test leading and trailing whitespace are not counted as characters`() { | ||
val before = "line1\nline2" | ||
val after = "line1\n line2" | ||
|
||
val metrics = getDiffMetrics(before, after) | ||
assertEquals(1, metrics.insertedLines) | ||
assertEquals(5, metrics.insertedCharacters) | ||
assertNotEquals(9, metrics.insertedCharacters) | ||
} | ||
} |