Skip to content

Commit 81dd90e

Browse files
author
C Tidd
committed
telemetry(amazonq): Add metrics utility to instrument generated patches applied to existing code.
1 parent e225cdc commit 81dd90e

File tree

2 files changed

+201
-0
lines changed
  • plugins/amazonq/chat/jetbrains-community
    • src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/util
    • tst/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/util

2 files changed

+201
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util
5+
6+
import com.intellij.diff.comparison.ComparisonManager
7+
import com.intellij.diff.comparison.ComparisonPolicy
8+
import com.intellij.diff.fragments.LineFragment
9+
import com.intellij.openapi.progress.EmptyProgressIndicator
10+
11+
data class DiffMetrics(
12+
val insertedLines: Int,
13+
val insertedCharacters: Int
14+
)
15+
16+
fun lineEnding(content: String, curr: Int, end: Int): Int {
17+
require (curr <= end) { "curr must be within end of range" }
18+
require (end <= content.length) { "end must be within content" }
19+
20+
return if (curr == end) {
21+
-1
22+
} else if (content[curr] == '\r') {
23+
if ((curr + 1 < end) && (content[curr + 1] == '\n')) {
24+
2
25+
} else {
26+
1
27+
}
28+
} else if (content[curr] == '\n') {
29+
1
30+
} else {
31+
-1
32+
}
33+
}
34+
35+
fun getDiffMetrics(before: String, after: String): DiffMetrics {
36+
val comparisonManager = ComparisonManager.getInstance()
37+
val fragments = comparisonManager.compareLines(
38+
before,
39+
after,
40+
ComparisonPolicy.DEFAULT,
41+
EmptyProgressIndicator()
42+
)
43+
44+
var accLineCount = 0
45+
var accCharCount = 0
46+
47+
fragments.forEach { fragment: LineFragment ->
48+
var curr = fragment.startOffset2
49+
val end = fragment.endOffset2
50+
51+
while (curr < end) {
52+
accLineCount += 1
53+
54+
// Consume leading whitespace:
55+
while (curr < end && lineEnding(after, curr, end) == -1 && after[curr].isWhitespace()) curr++
56+
57+
// Consume through EOL:
58+
val lineContentStart = curr
59+
while (curr < end && lineEnding(after, curr, end) == -1) curr++
60+
var lineContentEnd = curr
61+
curr += maxOf(lineEnding(after, curr, end), 0)
62+
63+
// Walk back trailing whitespace and record character count before continuing to next line:
64+
while (lineContentEnd > lineContentStart && after[lineContentEnd - 1].isWhitespace()) lineContentEnd--
65+
accCharCount += lineContentEnd - lineContentStart
66+
}
67+
}
68+
69+
return DiffMetrics(
70+
insertedLines = accLineCount,
71+
insertedCharacters = accCharCount,
72+
)
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util
5+
6+
import com.intellij.testFramework.LightPlatformTestCase
7+
import com.intellij.testFramework.TestApplicationManager
8+
import kotlin.test.assertNotEquals
9+
10+
class DiffMetricsTest : LightPlatformTestCase() {
11+
override fun setUp() {
12+
super.setUp()
13+
TestApplicationManager.getInstance()
14+
}
15+
16+
fun `test empty input`() {
17+
val metrics = getDiffMetrics("", "")
18+
assertEquals(0, metrics.insertedLines)
19+
assertEquals(0, metrics.insertedCharacters)
20+
}
21+
22+
fun `test insertions are counted`() {
23+
val before = """
24+
line1
25+
line2
26+
""".trimIndent()
27+
28+
val after = """
29+
line1
30+
inserted
31+
line2
32+
""".trimIndent()
33+
34+
val metrics = getDiffMetrics(before, after)
35+
assertEquals(1, metrics.insertedLines)
36+
assertEquals(8, metrics.insertedCharacters)
37+
}
38+
39+
fun `test modifications are counted`() {
40+
val before = """
41+
line1
42+
line2
43+
line3
44+
""".trimIndent()
45+
46+
val after = """
47+
line1
48+
modified
49+
line3
50+
""".trimIndent()
51+
52+
val metrics = getDiffMetrics(before, after)
53+
assertEquals(1, metrics.insertedLines)
54+
assertEquals(8, metrics.insertedCharacters)
55+
}
56+
57+
fun `test deletions are counted`() {
58+
val before = """
59+
line1
60+
line2
61+
line3
62+
""".trimIndent()
63+
64+
val after = """
65+
line1
66+
line3
67+
""".trimIndent()
68+
69+
val metrics = getDiffMetrics(before, after)
70+
assertEquals(0, metrics.insertedLines)
71+
assertEquals(0, metrics.insertedCharacters)
72+
}
73+
74+
fun `test multiline and multiple hunks are counted`() {
75+
val before = """
76+
line1
77+
line2
78+
line3
79+
""".trimIndent()
80+
81+
val after = """
82+
inserted1
83+
line1
84+
inserted2
85+
inserted3
86+
line3
87+
inserted4
88+
""".trimIndent()
89+
90+
val metrics = getDiffMetrics(before, after)
91+
assertEquals(4, metrics.insertedLines)
92+
assertEquals(36, metrics.insertedCharacters)
93+
}
94+
95+
fun `test empty lines are counted`() {
96+
val before = "line1"
97+
val after = "line1\n\nline2"
98+
val metrics = getDiffMetrics(before, after)
99+
assertEquals(2, metrics.insertedLines)
100+
assertEquals(5, metrics.insertedCharacters)
101+
}
102+
103+
fun `test trailing newline is not counted`() {
104+
val before = "line1"
105+
val after = "line1\nline2\n"
106+
val metrics = getDiffMetrics(before, after)
107+
assertEquals(1, metrics.insertedLines)
108+
assertEquals(5, metrics.insertedCharacters)
109+
}
110+
111+
fun `test newline sequences are counted`() {
112+
val before = "line1"
113+
val after = "line1\nline2\rline3\r\nline4"
114+
val metrics = getDiffMetrics(before, after)
115+
assertEquals(3, metrics.insertedLines)
116+
assertEquals(15, metrics.insertedCharacters)
117+
}
118+
119+
fun `test leading and trailing whitespace are not counted as characters`() {
120+
val before = "line1\nline2"
121+
val after = "line1\n line2"
122+
123+
val metrics = getDiffMetrics(before, after)
124+
assertEquals(1, metrics.insertedLines)
125+
assertEquals(5, metrics.insertedCharacters)
126+
assertNotEquals(9, metrics.insertedCharacters)
127+
}
128+
}

0 commit comments

Comments
 (0)