Skip to content

Commit 5ff34b8

Browse files
committed
fix: restore TEST_ATTRIBUTES in RUNNABLE, add TEST_INLINE_ATTRIBUTES group
Test attribute is runnable (stays in RUNNABLE_ATTRIBUTES) but not numbered (getAttributeOrder returns -1, line marker falls back to getLocationInfo). Numbering groups: DATA_ATTRIBUTES, TEST_INLINE_ATTRIBUTES, BENCH_ATTRIBUTES. https://claude.ai/code/session_01TmFvjfMtoxTvddQRBzsbPN
1 parent cdefecd commit 5ff34b8

6 files changed

Lines changed: 44 additions & 68 deletions

File tree

CLAUDE.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -141,25 +141,28 @@ The plugin registers extensions in `plugin.xml` under two namespaces:
141141

142142
The plugin recognizes PHP attributes defined in `TestoClasses.kt`. Constants are grouped into arrays for reuse across the codebase:
143143

144-
| Group (array) | Attributes (FQN) |
145-
|--------------------------|-----------------------------------------------------------------------------------|
146-
| `TEST_ATTRIBUTES` | `\Testo\Test`, `\Testo\Inline\TestInline` |
147-
| `DATA_ATTRIBUTES` | `\Testo\Data\DataProvider`, `\Testo\Data\DataSet`, `\Testo\Data\DataUnion`, `\Testo\Data\DataCross`, `\Testo\Data\DataZip` |
148-
| `BENCH_ATTRIBUTES` | `\Testo\Bench` |
144+
| Group (array) | Attributes (FQN) |
145+
|----------------------------|-----------------------------------------------------------------------------------|
146+
| `TEST_ATTRIBUTES` | `\Testo\Test`, `\Testo\Inline\TestInline` |
147+
| `TEST_INLINE_ATTRIBUTES` | `\Testo\Inline\TestInline` |
148+
| `DATA_ATTRIBUTES` | `\Testo\Data\DataProvider`, `\Testo\Data\DataSet`, `\Testo\Data\DataUnion`, `\Testo\Data\DataCross`, `\Testo\Data\DataZip` |
149+
| `BENCH_ATTRIBUTES` | `\Testo\Bench` |
149150

150151
Other constants: `ASSERT` (`\Testo\Assert`), `EXPECT` (`\Testo\Expect`), `ASSERTION_EXCEPTION`.
151152

152153
These arrays are spread into `RUNNABLE_ATTRIBUTES` (line markers) and `MEANINGFUL_ATTRIBUTES` (PsiUtil) — adding a new attribute to the group array automatically propagates it everywhere.
153154

154155
### Attribute Group Numbering
155156

156-
Attributes on a function/method are numbered **within their own group**, not globally. Each group has independent 0-based indexing:
157+
Attributes on a function/method are numbered **within their own group**, not globally. Each group has independent 0-based indexing. The groups are defined in `PsiUtil.ATTRIBUTE_GROUPS`:
157158

158-
- **test data** group: all `DATA_ATTRIBUTES` (DataProvider, DataSet, DataUnion, DataCross, DataZip) share one group — numbered together
159-
- **inline** group: each `TestInline` is numbered among other `TestInline` attributes (same FQN)
160-
- **bench** group: each `Bench` is numbered among other `Bench` attributes (same FQN)
159+
| Group | Source array | Used for |
160+
|-------------------|---------------------------|-----------------------------------------------|
161+
| test data | `DATA_ATTRIBUTES` | Data providers for `#[Test]` methods |
162+
| inline | `TEST_INLINE_ATTRIBUTES` | Inline test cases (`#[TestInline]`) |
163+
| bench | `BENCH_ATTRIBUTES` | Benchmark data (`#[Bench]`) |
161164

162-
Explicit multi-attribute groups are defined in `PsiUtil.ATTRIBUTE_GROUPS` (currently only `DATA_ATTRIBUTES`). All other meaningful attributes (except `Test`) are grouped by their own FQN — attributes with the same FQN form a group automatically.
165+
The `#[Test]` attribute itself is **not numbered** — it is a marker only. The method/function name already gets its own gutter line marker. `Test` IS included in `RUNNABLE_ATTRIBUTES` (it's runnable), but `getAttributeOrder` returns `-1` for it, and the line marker falls back to `getLocationInfo`.
163166

164167
The `#[Test]` attribute itself is **not numbered** — it is a marker only. The method/function name already gets its own gutter line marker.
165168

@@ -177,7 +180,7 @@ Example for a function `foo` with multiple attributes:
177180
#[Bench(...)] → type=bench, foo:1
178181
```
179182

180-
`RUNNABLE_ATTRIBUTES` (used for gutter line markers) contains `TestInline + BENCH_ATTRIBUTES + DATA_ATTRIBUTES` — it does **not** include `Test` since the method already gets a run marker via `getLocationInfo`.
183+
`RUNNABLE_ATTRIBUTES` (used for gutter line markers) contains `TEST_ATTRIBUTES + BENCH_ATTRIBUTES + DATA_ATTRIBUTES`.
181184

182185
### Test Detection Logic (mixin.kt)
183186

src/main/kotlin/com/github/xepozz/testo/TestoClasses.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ object TestoClasses {
3030
TEST,
3131
TEST_INLINE,
3232
)
33+
val TEST_INLINE_ATTRIBUTES = arrayOf(
34+
TEST_INLINE,
35+
)
3336
val BENCH_ATTRIBUTES = arrayOf(
3437
BENCH,
3538
)

src/main/kotlin/com/github/xepozz/testo/tests/TestoTestRunLineMarkerProvider.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ class TestoTestRunLineMarkerProvider : RunLineMarkerContributor() {
9696

9797
companion object Companion {
9898
val RUNNABLE_ATTRIBUTES = arrayOf(
99-
TestoClasses.TEST_INLINE,
99+
*TestoClasses.TEST_ATTRIBUTES,
100100
*TestoClasses.BENCH_ATTRIBUTES,
101101
*TestoClasses.DATA_ATTRIBUTES,
102102
)

src/main/kotlin/com/github/xepozz/testo/util/PsiUtil.kt

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,15 @@ object PsiUtil {
1515

1616
val ATTRIBUTE_GROUPS: Array<Array<String>> = arrayOf(
1717
TestoClasses.DATA_ATTRIBUTES,
18+
TestoClasses.TEST_INLINE_ATTRIBUTES,
19+
TestoClasses.BENCH_ATTRIBUTES,
1820
)
1921

20-
fun getAttributeGroup(fqn: String?): Array<String>? {
21-
if (fqn == null) return null
22-
val group = ATTRIBUTE_GROUPS.firstOrNull { fqn in it }
23-
if (group != null) return group
24-
if (fqn in MEANINGFUL_ATTRIBUTES && fqn != TestoClasses.TEST) return arrayOf(fqn)
25-
return null
26-
}
22+
fun getAttributeGroup(fqn: String?): Array<String>? =
23+
ATTRIBUTE_GROUPS.firstOrNull { fqn in it }
2724

2825
fun getAttributeOrder(attribute: PhpAttribute, owner: PhpAttributesOwner): Int {
29-
val fqn = attribute.fqn ?: return -1
30-
val group = getAttributeGroup(fqn) ?: return -1
26+
val group = getAttributeGroup(attribute.fqn) ?: return -1
3127
return owner.attributes
3228
.filter { it.fqn in group }
3329
.indexOf(attribute)

src/test/kotlin/com/github/xepozz/testo/PsiUtilTest.kt

Lines changed: 15 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -35,49 +35,42 @@ class PsiUtilTest : TestCase() {
3535

3636
fun testGetAttributeGroup_dataProviderInDataGroup() {
3737
val group = PsiUtil.getAttributeGroup(TestoClasses.DATA_PROVIDER)
38-
assertNotNull("DataProvider should have a group", group)
3938
assertSame(TestoClasses.DATA_ATTRIBUTES, group)
4039
}
4140

4241
fun testGetAttributeGroup_dataSetInDataGroup() {
4342
val group = PsiUtil.getAttributeGroup(TestoClasses.DATA_SET)
44-
assertNotNull("DataSet should have a group", group)
4543
assertSame(TestoClasses.DATA_ATTRIBUTES, group)
4644
}
4745

4846
fun testGetAttributeGroup_dataUnionInDataGroup() {
4947
val group = PsiUtil.getAttributeGroup(TestoClasses.DATA_UNION)
50-
assertNotNull("DataUnion should have a group", group)
5148
assertSame(TestoClasses.DATA_ATTRIBUTES, group)
5249
}
5350

5451
fun testGetAttributeGroup_dataCrossInDataGroup() {
5552
val group = PsiUtil.getAttributeGroup(TestoClasses.DATA_CROSS)
56-
assertNotNull("DataCross should have a group", group)
5753
assertSame(TestoClasses.DATA_ATTRIBUTES, group)
5854
}
5955

6056
fun testGetAttributeGroup_dataZipInDataGroup() {
6157
val group = PsiUtil.getAttributeGroup(TestoClasses.DATA_ZIP)
62-
assertNotNull("DataZip should have a group", group)
6358
assertSame(TestoClasses.DATA_ATTRIBUTES, group)
6459
}
6560

66-
fun testGetAttributeGroup_testInlineHasGroup() {
61+
fun testGetAttributeGroup_testInlineInInlineGroup() {
6762
val group = PsiUtil.getAttributeGroup(TestoClasses.TEST_INLINE)
68-
assertNotNull("TestInline should have a group", group)
69-
assertTrue(group!!.contains(TestoClasses.TEST_INLINE))
63+
assertSame(TestoClasses.TEST_INLINE_ATTRIBUTES, group)
7064
}
7165

72-
fun testGetAttributeGroup_benchHasGroup() {
66+
fun testGetAttributeGroup_benchInBenchGroup() {
7367
val group = PsiUtil.getAttributeGroup(TestoClasses.BENCH)
74-
assertNotNull("Bench should have a group", group)
75-
assertTrue(group!!.contains(TestoClasses.BENCH))
68+
assertSame(TestoClasses.BENCH_ATTRIBUTES, group)
7669
}
7770

7871
fun testGetAttributeGroup_testHasNoGroup() {
7972
val group = PsiUtil.getAttributeGroup(TestoClasses.TEST)
80-
assertNull("Plain Test attribute should not have a numbered group", group)
73+
assertNull("Test attribute is a marker, not numbered", group)
8174
}
8275

8376
fun testGetAttributeGroup_nullReturnsNull() {
@@ -88,26 +81,7 @@ class PsiUtilTest : TestCase() {
8881
assertNull(PsiUtil.getAttributeGroup("\\Some\\Unknown\\Attribute"))
8982
}
9083

91-
fun testGetAttributeGroup_allDataAttributesShareSameGroup() {
92-
val groups = TestoClasses.DATA_ATTRIBUTES.map { PsiUtil.getAttributeGroup(it) }
93-
val first = groups.first()
94-
for (group in groups) {
95-
assertSame("All data attributes should share the same group instance", first, group)
96-
}
97-
}
98-
99-
fun testGetAttributeGroup_inlineAndBenchAreSeparateGroups() {
100-
val inlineGroup = PsiUtil.getAttributeGroup(TestoClasses.TEST_INLINE)
101-
val benchGroup = PsiUtil.getAttributeGroup(TestoClasses.BENCH)
102-
assertNotNull(inlineGroup)
103-
assertNotNull(benchGroup)
104-
assertFalse(
105-
"Inline and bench groups should not overlap",
106-
inlineGroup!!.toSet().intersect(benchGroup!!.toSet()).isNotEmpty()
107-
)
108-
}
109-
110-
fun testAttributeGroups_allExplicitGroupsAreInMeaningful() {
84+
fun testAttributeGroups_allGroupedAttributesAreInMeaningful() {
11185
val meaningful = PsiUtil.MEANINGFUL_ATTRIBUTES.toSet()
11286
for (group in PsiUtil.ATTRIBUTE_GROUPS) {
11387
for (attr in group) {
@@ -116,7 +90,7 @@ class PsiUtilTest : TestCase() {
11690
}
11791
}
11892

119-
fun testAttributeGroups_noOverlapBetweenExplicitGroups() {
93+
fun testAttributeGroups_noOverlapBetweenGroups() {
12094
val groups = PsiUtil.ATTRIBUTE_GROUPS
12195
for (i in groups.indices) {
12296
for (j in i + 1 until groups.size) {
@@ -125,4 +99,12 @@ class PsiUtilTest : TestCase() {
12599
}
126100
}
127101
}
102+
103+
fun testAttributeGroups_totalCount() {
104+
val totalGrouped = PsiUtil.ATTRIBUTE_GROUPS.sumOf { it.size }
105+
val expectedGrouped = TestoClasses.DATA_ATTRIBUTES.size +
106+
TestoClasses.TEST_INLINE_ATTRIBUTES.size +
107+
TestoClasses.BENCH_ATTRIBUTES.size
108+
assertEquals(expectedGrouped, totalGrouped)
109+
}
128110
}

src/test/kotlin/com/github/xepozz/testo/TestoLineMarkerCompanionTest.kt

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,17 @@ class TestoLineMarkerCompanionTest : TestCase() {
1919
}
2020
}
2121

22-
fun testRunnableAttributes_containsBenchAttribute() {
22+
fun testRunnableAttributes_containsTestAttributes() {
2323
val runnable = TestoTestRunLineMarkerProvider.RUNNABLE_ATTRIBUTES.toSet()
24-
assertTrue("Should contain \\Testo\\Bench", runnable.contains(TestoClasses.BENCH))
25-
}
26-
27-
fun testRunnableAttributes_containsTestInline() {
28-
val runnable = TestoTestRunLineMarkerProvider.RUNNABLE_ATTRIBUTES.toSet()
29-
assertTrue("Missing TestInline attribute", runnable.contains(TestoClasses.TEST_INLINE))
30-
}
31-
32-
fun testRunnableAttributes_doesNotContainPlainTestAttribute() {
33-
val runnable = TestoTestRunLineMarkerProvider.RUNNABLE_ATTRIBUTES.toSet()
34-
assertFalse("Should not contain plain Test attribute", runnable.contains(TestoClasses.TEST))
24+
for (attr in TestoClasses.TEST_ATTRIBUTES) {
25+
assertTrue("Missing test attribute: $attr", runnable.contains(attr))
26+
}
3527
}
3628

3729
fun testRunnableAttributes_totalCount() {
38-
val expected = TestoClasses.DATA_ATTRIBUTES.size +
30+
val expected = TestoClasses.TEST_ATTRIBUTES.size +
3931
TestoClasses.BENCH_ATTRIBUTES.size +
40-
1 // TestInline
32+
TestoClasses.DATA_ATTRIBUTES.size
4133
assertEquals(expected, TestoTestRunLineMarkerProvider.RUNNABLE_ATTRIBUTES.size)
4234
}
4335
}

0 commit comments

Comments
 (0)