Skip to content

Commit 1b7f1e5

Browse files
ruromeroclaude
andcommitted
fix(python): use PEP 508 string containment for in/not in operators
The `in` and `not in` marker operators were incorrectly splitting by comma and checking array membership. Per PEP 508, these operators perform Python string containment (e.g. `'linux' in 'linux2'` is true). TC-4313 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent c1eff82 commit 1b7f1e5

2 files changed

Lines changed: 49 additions & 2 deletions

File tree

src/providers/marker_evaluator.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ function evaluateComparison(variable, op, value, env) {
8888
switch (op) {
8989
case '==': return envVal === value
9090
case '!=': return envVal !== value
91-
case 'in': return value.split(',').map(s => s.trim()).includes(envVal)
92-
case 'not in': return !value.split(',').map(s => s.trim()).includes(envVal)
91+
case 'in': return value.includes(envVal)
92+
case 'not in': return !value.includes(envVal)
9393
default: return envVal === value
9494
}
9595
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { expect } from 'chai'
2+
3+
import { evaluateMarker } from '../../src/providers/marker_evaluator.js'
4+
5+
let originalPlatform
6+
7+
suite('PEP 508 marker evaluator', () => {
8+
suiteSetup(() => {
9+
originalPlatform = process.platform
10+
Object.defineProperty(process, 'platform', { value: 'linux', configurable: true })
11+
})
12+
suiteTeardown(() => {
13+
Object.defineProperty(process, 'platform', { value: originalPlatform, configurable: true })
14+
})
15+
16+
suite('in operator — PEP 508 string containment', () => {
17+
test('substring match: sys_platform in wider string', () => {
18+
expect(evaluateMarker("sys_platform in 'linux2'")).to.be.true
19+
})
20+
21+
test('exact match: sys_platform in exact string', () => {
22+
expect(evaluateMarker("sys_platform in 'linux'")).to.be.true
23+
})
24+
25+
test('no match: sys_platform in unrelated string', () => {
26+
expect(evaluateMarker("sys_platform in 'win32'")).to.be.false
27+
})
28+
29+
test('partial overlap but no containment', () => {
30+
expect(evaluateMarker("sys_platform in 'lin'")).to.be.false
31+
})
32+
})
33+
34+
suite('not in operator — negated string containment', () => {
35+
test('substring present: sys_platform not in wider string', () => {
36+
expect(evaluateMarker("sys_platform not in 'linux2'")).to.be.false
37+
})
38+
39+
test('no match: sys_platform not in unrelated string', () => {
40+
expect(evaluateMarker("sys_platform not in 'win32'")).to.be.true
41+
})
42+
43+
test('partial overlap negated', () => {
44+
expect(evaluateMarker("sys_platform not in 'lin'")).to.be.true
45+
})
46+
})
47+
})

0 commit comments

Comments
 (0)