Skip to content

Commit 97aa1c9

Browse files
Steve RamageSJrX
authored andcommitted
feat: Add support for ~30 new systemd networking values (Resolves #373)
1 parent ef1dc06 commit 97aa1c9

File tree

6 files changed

+166
-10
lines changed

6 files changed

+166
-10
lines changed

src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/SemanticDataRepository.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ class SemanticDataRepository private constructor() {
154154
validatorMap.putAll(RlimitOptionValue.validators) // Scopes are not supported since they aren't standard unit files.
155155
validatorMap.putAll(NetworkAddressOptionValue.validators)
156156
validatorMap.putAll(InAddrPrefixesOptionValue.validators)
157+
validatorMap.putAll(UIntOptionValues.validators)
157158
fileClassToSectionNameToKeyValuesFromDoc["unit"]?.remove(SCOPE_KEYWORD)
158159
fileClassToSectionToKeyAndValidatorMap["unit"]?.remove(SCOPE_KEYWORD)
159160
}
@@ -706,7 +707,7 @@ unit types. These options are documented in <a href="http://man7.org/linux/man-p
706707
"Link", "Match", "SR-IOV",
707708
)
708709
"Netdev" -> setOf(
709-
"BareUDP", "BatmanAdvanced", "Bond", "Bridge", "FooOverUDP", "GENEVE", "IPoIB", "IPVLAN", "IPVTAP",
710+
"BareUDP", "BatmanAdvanced", "Bond", "Bridge", "FooOverUDP", "GENEVE", "HSR", "IPoIB", "IPVLAN", "IPVTAP",
710711
"L2TP", "L2TPSession", "MACsec", "MACsecReceiveAssociation", "MACsecReceiveChannel", "MACsecTransmitAssociation", "MACVLAN",
711712
"MACVTAP", "Match", "NetDev", "Peer", "Tap", "Tun", "Tunnel", "VLAN",
712713
"VRF", "VXCAN", "VXLAN", "WireGuard", "WireGuardPeer", "WLAN", "Xfrm", "NetDev"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues
2+
3+
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.Validator
4+
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.*
5+
6+
7+
8+
class UIntOptionValues(validatorName: String, grammar: Combinator) : GrammarOptionValue(validatorName, grammar) {
9+
10+
companion object {
11+
12+
val validators = mapOf(
13+
Validator("config_parse_uint32", "0") to UIntOptionValues("config_parse_uint32", SequenceCombinator(IntegerTerminal(0, 4_294_967_296 ), EOF())),
14+
Validator("config_parse_uint16", "0") to UIntOptionValues("config_parse_uint16", SequenceCombinator(IntegerTerminal(0, 65536), EOF())),
15+
Validator("config_parse_uint8", "0") to UIntOptionValues("config_parse_uint8", SequenceCombinator(IntegerTerminal(0, 256), EOF())),
16+
)
17+
}
18+
}
19+

src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/grammar/IntegerTerminal.kt

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar
22

3-
class IntegerTerminal(private val minInclusive: Int,private val maxExclusive: Int) : TerminalCombinator {
3+
class IntegerTerminal(private val minInclusive: Long,private val maxExclusive: Long) : TerminalCombinator {
4+
5+
constructor(minInclusive: Int, maxExclusive: Int) : this(minInclusive.toLong(), maxExclusive.toLong())
46

57
val intRegex = "-?[0-9]+".toRegex()
68

@@ -14,13 +16,17 @@ class IntegerTerminal(private val minInclusive: Int,private val maxExclusive: In
1416
override fun SemanticMatch(value: String, offset: Int): MatchResult {
1517
val matchResult = intRegex.matchAt(value, offset) ?: return NoMatch
1618

17-
val intValue = matchResult.value.toInt()
19+
try {
20+
val intValue = matchResult.value.toLong()
21+
22+
if (intValue < minInclusive || intValue >= maxExclusive) {
23+
return NoMatch.copy(longestMatch = offset)
24+
}
1825

19-
if (intValue < minInclusive || intValue >= maxExclusive) {
26+
return MatchResult(listOf(matchResult.value), offset + matchResult.value.length, listOf(this), offset + matchResult.value.length)
27+
} catch (e: NumberFormatException) {
2028
return NoMatch.copy(longestMatch = offset)
2129
}
22-
23-
return MatchResult(listOf(matchResult.value), offset + matchResult.value.length, listOf(this), offset + matchResult.value.length)
2430
}
2531

2632
override fun toString(): String {

src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/annotators/InvalidSectionHeaderNameAnnotatorTest.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -524,9 +524,9 @@ class InvalidSectionHeaderNameAnnotatorTest : AbstractUnitFileTest() {
524524

525525
val highlightTexts = highlights.map { it.description }
526526

527-
assertContainsElements(highlightTexts, "The section Unit is not allowed in Netdev files, only the following are allowed: [BareUDP, BatmanAdvanced, Bond, Bridge, FooOverUDP, GENEVE, IPoIB, IPVLAN, IPVTAP, L2TP, L2TPSession, MACsec, MACsecReceiveAssociation, MACsecReceiveChannel, MACsecTransmitAssociation, MACVLAN, MACVTAP, Match, NetDev, Peer, Tap, Tun, Tunnel, VLAN, VRF, VXCAN, VXLAN, WireGuard, WireGuardPeer, WLAN, Xfrm]")
528-
assertContainsElements(highlightTexts, "The section Install is not allowed in Netdev files, only the following are allowed: [BareUDP, BatmanAdvanced, Bond, Bridge, FooOverUDP, GENEVE, IPoIB, IPVLAN, IPVTAP, L2TP, L2TPSession, MACsec, MACsecReceiveAssociation, MACsecReceiveChannel, MACsecTransmitAssociation, MACVLAN, MACVTAP, Match, NetDev, Peer, Tap, Tun, Tunnel, VLAN, VRF, VXCAN, VXLAN, WireGuard, WireGuardPeer, WLAN, Xfrm]")
529-
assertContainsElements(highlightTexts, "The section Service is not allowed in Netdev files, only the following are allowed: [BareUDP, BatmanAdvanced, Bond, Bridge, FooOverUDP, GENEVE, IPoIB, IPVLAN, IPVTAP, L2TP, L2TPSession, MACsec, MACsecReceiveAssociation, MACsecReceiveChannel, MACsecTransmitAssociation, MACVLAN, MACVTAP, Match, NetDev, Peer, Tap, Tun, Tunnel, VLAN, VRF, VXCAN, VXLAN, WireGuard, WireGuardPeer, WLAN, Xfrm]")
527+
assertContainsElements(highlightTexts, "The section Unit is not allowed in Netdev files, only the following are allowed: [BareUDP, BatmanAdvanced, Bond, Bridge, FooOverUDP, GENEVE, HSR, IPoIB, IPVLAN, IPVTAP, L2TP, L2TPSession, MACsec, MACsecReceiveAssociation, MACsecReceiveChannel, MACsecTransmitAssociation, MACVLAN, MACVTAP, Match, NetDev, Peer, Tap, Tun, Tunnel, VLAN, VRF, VXCAN, VXLAN, WireGuard, WireGuardPeer, WLAN, Xfrm]")
528+
assertContainsElements(highlightTexts, "The section Install is not allowed in Netdev files, only the following are allowed: [BareUDP, BatmanAdvanced, Bond, Bridge, FooOverUDP, GENEVE, HSR, IPoIB, IPVLAN, IPVTAP, L2TP, L2TPSession, MACsec, MACsecReceiveAssociation, MACsecReceiveChannel, MACsecTransmitAssociation, MACVLAN, MACVTAP, Match, NetDev, Peer, Tap, Tun, Tunnel, VLAN, VRF, VXCAN, VXLAN, WireGuard, WireGuardPeer, WLAN, Xfrm]")
529+
assertContainsElements(highlightTexts, "The section Service is not allowed in Netdev files, only the following are allowed: [BareUDP, BatmanAdvanced, Bond, Bridge, FooOverUDP, GENEVE, HSR, IPoIB, IPVLAN, IPVTAP, L2TP, L2TPSession, MACsec, MACsecReceiveAssociation, MACsecReceiveChannel, MACsecTransmitAssociation, MACVLAN, MACVTAP, Match, NetDev, Peer, Tap, Tun, Tunnel, VLAN, VRF, VXCAN, VXLAN, WireGuard, WireGuardPeer, WLAN, Xfrm]")
530530
}
531531

532532
fun testServiceSectionsInNetworkFileHasWarnings() {
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package net.sjrx.intellij.plugins.systemdunitfiles.inspections
2+
3+
import junit.framework.TestCase
4+
import net.sjrx.intellij.plugins.systemdunitfiles.AbstractUnitFileTest
5+
6+
class InvalidValueInspectionForUIntOptionValue : AbstractUnitFileTest() {
7+
8+
fun testWeakWarningWhenNegativeIntegerSpecified() {
9+
// Fixture Setup
10+
// language="unit file (systemd)"
11+
val file = """
12+
[VXLAN]
13+
# uint32
14+
VNI=-1
15+
16+
[Bridge]
17+
# uint16
18+
Priority=-2
19+
20+
[HSR]
21+
# uint8
22+
Supervision=-3
23+
""".trimIndent()
24+
25+
26+
// Execute SUT
27+
setupFileInEditor("file.netdev", file)
28+
enableInspection(InvalidValueInspection::class.java)
29+
val highlights = myFixture.doHighlighting()
30+
31+
// Verification
32+
assertSize(3, highlights)
33+
var info = highlights[0]
34+
assertStringContains("is correctly formatted but seems invalid", info!!.description)
35+
TestCase.assertEquals("-1", info.text)
36+
37+
info = highlights[1]
38+
assertStringContains("is correctly formatted but seems invalid", info!!.description)
39+
TestCase.assertEquals("-2", info.text)
40+
41+
info = highlights[2]
42+
assertStringContains("is correctly formatted but seems invalid", info!!.description)
43+
TestCase.assertEquals("-3", info.text)
44+
}
45+
46+
fun testWeakWarningWhenTooBigAnIntegerSpecified() {
47+
// Fixture Setup
48+
// language="unit file (systemd)"
49+
val file = """
50+
[VXLAN]
51+
# uint32
52+
VNI=9999999999
53+
54+
[Bridge]
55+
# uint16
56+
Priority=65536
57+
58+
[HSR]
59+
# uint8
60+
Supervision=256
61+
""".trimIndent()
62+
63+
64+
// Execute SUT
65+
setupFileInEditor("file.netdev", file)
66+
enableInspection(InvalidValueInspection::class.java)
67+
val highlights = myFixture.doHighlighting()
68+
69+
// Verification
70+
assertSize(3, highlights)
71+
var info = highlights[0]
72+
assertStringContains("is correctly formatted but seems invalid", info!!.description)
73+
TestCase.assertEquals("9999999999", info.text)
74+
75+
info = highlights[1]
76+
assertStringContains("is correctly formatted but seems invalid", info!!.description)
77+
TestCase.assertEquals("65536", info.text)
78+
79+
info = highlights[2]
80+
assertStringContains("is correctly formatted but seems invalid", info!!.description)
81+
TestCase.assertEquals("256", info.text)
82+
}
83+
84+
fun testNoWeakWarningOnBoundaryConditions() {
85+
// Fixture Setup
86+
// language="unit file (systemd)"
87+
val file = """
88+
[VXLAN]
89+
# uint32
90+
VNI=0
91+
VNI=1
92+
VNI=4294967295
93+
VNI=4294967294
94+
VNI=2294967294
95+
VNI=2094967294
96+
VNI=65536
97+
VNI=65534
98+
99+
[Bridge]
100+
# uint16
101+
Priority=0
102+
Priority=1
103+
Priority=65535
104+
105+
[HSR]
106+
# uint8
107+
Supervision=0
108+
Supervision=1
109+
Supervision=255
110+
""".trimIndent()
111+
112+
// Execute SUT
113+
setupFileInEditor("file.netdev", file)
114+
enableInspection(InvalidValueInspection::class.java)
115+
val highlights = myFixture.doHighlighting()
116+
117+
// Verification
118+
assertSize(0, highlights)
119+
}
120+
121+
}

src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/OptionValueTest.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import net.sjrx.intellij.plugins.systemdunitfiles.AbstractUnitFileTest
44
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.FileClass
55
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.SemanticDataRepository
66
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.Validator
7+
import java.time.LocalDate
8+
import java.time.temporal.ChronoUnit
79

810
class OptionValueTest : AbstractUnitFileTest() {
911

@@ -35,7 +37,14 @@ class OptionValueTest : AbstractUnitFileTest() {
3537

3638
println("Missing:$totalMissingValidators")
3739
println("Found:$totalFoundValidators")
38-
val allowed = 1183
40+
41+
val startDate = LocalDate.of(2025, 7, 12) // Today's date
42+
val startingCount = 1183 // Your current undocumented options count
43+
val currentDate = LocalDate.now()
44+
val daysSinceStart = ChronoUnit.DAYS.between(startDate, currentDate)
45+
val reductionPerDay = 4
46+
val allowed = maxOf(0, startingCount - (daysSinceStart * reductionPerDay))
47+
3948
if (totalMissingValidators >= allowed) {
4049
assertEquals("Number of missing validators is too high at ${totalMissingValidators} > $allowed vs. found ${totalFoundValidators}", sortedList, "")
4150
}

0 commit comments

Comments
 (0)