Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ fun getAllAIGeneratedValidators(): Map<Validator, OptionValueInformation> {
Validator("config_parse_nexthop_section", "NEXTHOP_GROUP") to ConfigParseNexthopSectionOptionValue() as OptionValueInformation,
Validator("config_parse_nexthop_section", "NEXTHOP_ID") to ConfigParseNexthopSectionOptionValue() as OptionValueInformation,
Validator("config_parse_nexthop_section", "NEXTHOP_ONLINK") to ConfigParseNexthopSectionOptionValue() as OptionValueInformation,
Validator("config_parse_nsec", "0") to ConfigParseNsecOptionValue() as OptionValueInformation,
Validator("config_parse_permille", "0") to ConfigParsePermilleOptionValue() as OptionValueInformation,
Validator("config_parse_pfifo_size", "QDISC_KIND_PFIFO") to ConfigParsePfifoSizeOptionValue() as OptionValueInformation,
Validator("config_parse_pfifo_size", "QDISC_KIND_PFIFO_HEAD_DROP") to ConfigParsePfifoSizeOptionValue() as OptionValueInformation,
Validator("config_parse_pid2", "0") to ConfigParsePid2OptionValue() as OptionValueInformation,
Expand Down Expand Up @@ -167,6 +169,8 @@ fun getAllAIGeneratedValidators(): Map<Validator, OptionValueInformation> {
Validator("config_parse_sr_iov_num_vfs", "0") to ConfigParseSrIovNumVfsOptionValue() as OptionValueInformation,
Validator("config_parse_sr_iov_vlan_proto", "0") to ConfigParseSrIovVlanProtoOptionValue() as OptionValueInformation,
Validator("config_parse_swap_priority", "0") to ConfigParseSwapPriorityOptionValue() as OptionValueInformation,
Validator("config_parse_tasks_max", "0") to ConfigParseTasksMaxOptionValue() as OptionValueInformation,
Validator("config_parse_tbf_size", "QDISC_KIND_TBF") to ConfigParseTbfSizeOptionValue() as OptionValueInformation,
Validator("config_parse_tcp_window", "0") to ConfigParseTcpWindowOptionValue() as OptionValueInformation,
Validator("config_parse_timezone_mode", "0") to ConfigParseTimezoneModeOptionValue() as OptionValueInformation,
Validator("config_parse_trigger_unit", "0") to ConfigParseTriggerUnitOptionValue() as OptionValueInformation,
Expand All @@ -176,6 +180,7 @@ fun getAllAIGeneratedValidators(): Map<Validator, OptionValueInformation> {
Validator("config_parse_unit_condition_string", "CONDITION_CONTROL_GROUP_CONTROLLER") to ConfigParseUnitConditionStringOptionValue() as OptionValueInformation,
Validator("config_parse_unit_condition_string", "CONDITION_CPU_FEATURE") to ConfigParseUnitConditionStringOptionValue() as OptionValueInformation,
Validator("config_parse_unit_condition_string", "CONDITION_FIRST_BOOT") to ConfigParseUnitConditionStringOptionValue() as OptionValueInformation,
Validator("config_parse_unit_slice", "0") to ConfigParseUnitSliceOptionValue() as OptionValueInformation,
Validator("config_parse_use_domains", "0") to ConfigParseUseDomainsOptionValue() as OptionValueInformation,
Validator("config_parse_userns_chown", "0") to ConfigParseUsernsChownOptionValue() as OptionValueInformation,
Validator("config_parse_userns_ownership", "0") to ConfigParseUsernsOwnershipOptionValue() as OptionValueInformation,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai

import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.*

/**
* Validator for nanosecond-time options such as TimerSlackNSec=.
*
* C function: defined via DEFINE_PARSER(nsec, ..., parse_nsec) in src/shared/conf-parser.c,
* which delegates to parse_nsec in src/basic/time-util.c. parse_nsec accepts "infinity" or
* one or more numeric terms with optional unit suffix (s/ms/us/ns/min/h/d/w/M/y...). The same
* syntax that TIME_VALUE encodes for the parse_sec family applies here; only the default
* (suffix-less) multiplier differs.
*/
class ConfigParseNsecOptionValue : SimpleGrammarOptionValues(
"config_parse_nsec",
SequenceCombinator(
OptionalWhitespacePrefix(TIME_VALUE),
EOF()
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai

import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.*

/**
* Validator for permille (parts-per-thousand) options such as CAN.SamplePoint=.
*
* C function: config_parse_permille in src/shared/conf-parser.c → parse_permille in
* src/basic/percent-util.c. Accepts either:
* - "N‰" (integer 0..1000)
* - "N%" or "N.x%" (0..100% via tenths place, internally translated to 0..1000)
*
* Only the ASCII percent form is matched here; the ‰ Unicode suffix is syntactically rare.
*/
class ConfigParsePermilleOptionValue : SimpleGrammarOptionValues(
"config_parse_permille",
SequenceCombinator(
AlternativeCombinator(
// 0..99(.x)?%
SequenceCombinator(IntegerTerminal(0, 100), ZeroOrOne(RegexTerminal("\\.[0-9]", "\\.[0-9]")), LiteralChoiceTerminal("%")),
// 100% or 100.0%
SequenceCombinator(LiteralChoiceTerminal("100"), ZeroOrOne(LiteralChoiceTerminal(".0")), LiteralChoiceTerminal("%"))
),
EOF()
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai

import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.*

/**
* Validator for TasksMax=.
*
* C function: config_parse_tasks_max in src/core/load-fragment.c. The accepted values are:
* - "infinity"
* - a permyriad form: parse_permyriad accepts N%, N.N%, N.NN%, N‰, N.N‰, or N‱
* (bounded 0..10000). Only the ASCII percent form is matched here; the ‰/‱ Unicode
* suffixes are syntactically rare in unit files.
* - a strictly positive uint64 via safe_atou64 (>0 and <UINT64_MAX).
*
* Suffix-less "0" is rejected by the C parser (safe_atou64 returns 0 which fails the v<=0
* guard); "0%" is accepted (permyriad 0). The grammar below reflects that asymmetry.
*/
class ConfigParseTasksMaxOptionValue : SimpleGrammarOptionValues(
"config_parse_tasks_max",
SequenceCombinator(
AlternativeCombinator(
FlexibleLiteralChoiceTerminal("infinity"),
// Permyriad via %: 0..100 with up to two decimal places.
SequenceCombinator(
AlternativeCombinator(
SequenceCombinator(IntegerTerminal(0, 100), ZeroOrOne(RegexTerminal("\\.[0-9]{1,2}", "\\.[0-9]{1,2}"))),
SequenceCombinator(LiteralChoiceTerminal("100"), ZeroOrOne(RegexTerminal("\\.0{1,2}", "\\.0{1,2}")))
),
LiteralChoiceTerminal("%")
),
// Strictly positive integer.
RegexTerminal("[0-9]+", "[1-9][0-9]*")
),
EOF()
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai

import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.*

/**
* Validator for the TokenBucketFilter size-style options: BurstBytes, LimitBytes, MTUBytes,
* MPUBytes (and the deprecated Burst / LimitSize aliases).
*
* C function: config_parse_tbf_size(QDISC_KIND_TBF) in src/network/tc/tbf.c. After branching
* on the lvalue, it calls parse_size(rvalue, 1024, &k), so the value is a decimal byte count
* optionally suffixed with an IEC unit. Mirrors the existing config_parse_fq_size validator.
*/
class ConfigParseTbfSizeOptionValue : SimpleGrammarOptionValues(
"config_parse_tbf_size",
SequenceCombinator(
OptionalWhitespacePrefix(BYTES),
EOF()
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai

import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.*

/**
* Validator for Slice= (the unit's enclosing slice).
*
* C function: config_parse_unit_slice in src/core/load-fragment.c. It calls unit_name_printf
* (which expands specifiers like %p/%n) and then manager_load_unit, which validates that the
* resolved name is a real slice unit. Pre-expansion, the value must be a single token; if it
* contains specifiers it can produce anything, otherwise it must already look like a slice
* (ends in ".slice"). Whitespace-separated lists are not accepted.
*/
class ConfigParseUnitSliceOptionValue : SimpleGrammarOptionValues(
"config_parse_unit_slice",
SequenceCombinator(
AlternativeCombinator(
// Literal slice unit name: no whitespace, must end in .slice
RegexTerminal("\\S+", "[^\\s%]+\\.slice"),
// Contains a specifier — expansion can produce any unit name
RegexTerminal("\\S+", "\\S*%\\S+|\\S+%\\S*")
),
EOF()
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package net.sjrx.intellij.plugins.systemdunitfiles.inspections.ai

import net.sjrx.intellij.plugins.systemdunitfiles.AbstractUnitFileTest
import net.sjrx.intellij.plugins.systemdunitfiles.inspections.InvalidValueInspection
import org.junit.Test

class ConfigParseNsecOptionValueTest : AbstractUnitFileTest() {

@Test
fun testValidValues() {
// language="unit file (systemd)"
val file = """
[Service]
TimerSlackNSec=infinity
TimerSlackNSec=50
TimerSlackNSec=100us
TimerSlackNSec=1ms
TimerSlackNSec=10s
TimerSlackNSec=1min
TimerSlackNSec=2h
TimerSlackNSec=1d
TimerSlackNSec=1s 500ms
""".trimIndent()

setupFileInEditor("file.service", file)
enableInspection(InvalidValueInspection::class.java)
val highlights = myFixture.doHighlighting()

assertSize(0, highlights)
}

@Test
fun testInvalidValues() {
// language="unit file (systemd)"
val file = """
[Service]
TimerSlackNSec=<error descr="Invalid value">abc</error>
TimerSlackNSec=<error descr="Invalid value">-1</error>
TimerSlackNSec=<error descr="Invalid value">10zz</error>
""".trimIndent()

setupFileInEditor("file.service", file)
enableInspection(InvalidValueInspection::class.java)
val highlights = myFixture.doHighlighting()

assertSize(3, highlights)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package net.sjrx.intellij.plugins.systemdunitfiles.inspections.ai

import net.sjrx.intellij.plugins.systemdunitfiles.AbstractUnitFileTest
import net.sjrx.intellij.plugins.systemdunitfiles.inspections.InvalidValueInspection
import org.junit.Test

class ConfigParsePermilleOptionValueTest : AbstractUnitFileTest() {

@Test
fun testValidValues() {
// language="unit file (systemd)"
val file = """
[CAN]
SamplePoint=0%
SamplePoint=50%
SamplePoint=87.5%
SamplePoint=99%
SamplePoint=99.9%
SamplePoint=100%
SamplePoint=100.0%
DataSamplePoint=75%
DataSamplePoint=12.3%
""".trimIndent()

setupFileInEditor("file.network", file)
enableInspection(InvalidValueInspection::class.java)
val highlights = myFixture.doHighlighting()

assertSize(0, highlights)
}

@Test
fun testInvalidValues() {
// language="unit file (systemd)"
val file = """
[CAN]
SamplePoint=<error descr="Invalid value">50</error>
SamplePoint=<error descr="Invalid value">100.5%</error>
SamplePoint=<error descr="Invalid value">101%</error>
SamplePoint=<error descr="Invalid value">200%</error>
SamplePoint=<error descr="Invalid value">abc</error>
SamplePoint=<error descr="Invalid value">50.12%</error>
SamplePoint=<error descr="Invalid value">-5%</error>
""".trimIndent()

setupFileInEditor("file.network", file)
enableInspection(InvalidValueInspection::class.java)
val highlights = myFixture.doHighlighting()

assertSize(7, highlights)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package net.sjrx.intellij.plugins.systemdunitfiles.inspections.ai

import net.sjrx.intellij.plugins.systemdunitfiles.AbstractUnitFileTest
import net.sjrx.intellij.plugins.systemdunitfiles.inspections.InvalidValueInspection
import org.junit.Test

class ConfigParseTasksMaxOptionValueTest : AbstractUnitFileTest() {

@Test
fun testValidValues() {
// language="unit file (systemd)"
val file = """
[Service]
TasksMax=infinity
TasksMax=1
TasksMax=512
TasksMax=999999999
TasksMax=0%
TasksMax=50%
TasksMax=99.9%
TasksMax=12.34%
TasksMax=100%
TasksMax=100.0%
TasksMax=100.00%
""".trimIndent()

setupFileInEditor("file.service", file)
enableInspection(InvalidValueInspection::class.java)
val highlights = myFixture.doHighlighting()

assertSize(0, highlights)
}

@Test
fun testInvalidValues() {
// language="unit file (systemd)"
val file = """
[Service]
TasksMax=<error descr="Invalid value">0</error>
TasksMax=<error descr="Invalid value">-1</error>
TasksMax=<error descr="Invalid value">abc</error>
TasksMax=<error descr="Invalid value">100.5%</error>
TasksMax=<error descr="Invalid value">250%</error>
TasksMax=<error descr="Invalid value">50.123%</error>
TasksMax=<error descr="Invalid value">infinity 1</error>
""".trimIndent()

setupFileInEditor("file.service", file)
enableInspection(InvalidValueInspection::class.java)
val highlights = myFixture.doHighlighting()

assertSize(7, highlights)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package net.sjrx.intellij.plugins.systemdunitfiles.inspections.ai

import net.sjrx.intellij.plugins.systemdunitfiles.AbstractUnitFileTest
import net.sjrx.intellij.plugins.systemdunitfiles.inspections.InvalidValueInspection
import org.junit.Test

class ConfigParseTbfSizeOptionValueTest : AbstractUnitFileTest() {

@Test
fun testValidValues() {
// language="unit file (systemd)"
val file = """
[TokenBucketFilter]
BurstBytes=1024
LimitBytes=64K
MTUBytes=1500
MPUBytes=64
BurstBytes=1M
LimitBytes=1G
MTUBytes=2T
""".trimIndent()

setupFileInEditor("file.network", file)
enableInspection(InvalidValueInspection::class.java)
val highlights = myFixture.doHighlighting()

assertSize(0, highlights)
}

@Test
fun testInvalidValues() {
// language="unit file (systemd)"
val file = """
[TokenBucketFilter]
BurstBytes=<error descr="Invalid value">abc</error>
LimitBytes=<error descr="Invalid value">-1</error>
MTUBytes=<error descr="Invalid value">10X</error>
""".trimIndent()

setupFileInEditor("file.network", file)
enableInspection(InvalidValueInspection::class.java)
val highlights = myFixture.doHighlighting()

assertSize(3, highlights)
}
}
Loading
Loading