@@ -18,4 +18,181 @@ $h = @{
1818 $hashTableAst | Should - BeOfType [System.Management.Automation.Language.HashTableAst ]
1919 $hashTableAst.Extent.Text | Should - Be ' @{ z = "hi" }'
2020 }
21+
22+ Context ' Braced Member Access Ranges' {
23+
24+ BeforeDiscovery {
25+ $RangeTests = @ (
26+ @ {
27+ Name = ' No braced member access'
28+ ScriptDef = ' $object.Prop'
29+ ExpectedRanges = @ ()
30+ }
31+ @ {
32+ Name = ' No braced member access on braced variable name'
33+ ScriptDef = ' ${object}.Prop'
34+ ExpectedRanges = @ ()
35+ }
36+ @ {
37+ Name = ' Braced member access'
38+ ScriptDef = ' $object.{Prop}'
39+ ExpectedRanges = @ (
40+ , @ (8 , 14 )
41+ )
42+ }
43+ @ {
44+ Name = ' Braced member access with spaces'
45+ ScriptDef = ' $object. { Prop }'
46+ ExpectedRanges = @ (
47+ , @ (9 , 17 )
48+ )
49+ }
50+ @ {
51+ Name = ' Braced member access with newline'
52+ ScriptDef = " `$ object.`n { Prop }"
53+ ExpectedRanges = @ (
54+ , @ (9 , 17 )
55+ )
56+ }
57+ @ {
58+ Name = ' Braced member access with comment'
59+ ScriptDef = " `$ object. <#comment#>{Prop}"
60+ ExpectedRanges = @ (
61+ , @ (20 , 26 )
62+ )
63+ }
64+ @ {
65+ Name = ' Braced member access with multi-line comment'
66+ ScriptDef = " `$ object. <#`n comment`n #>{Prop}"
67+ ExpectedRanges = @ (
68+ , @ (22 , 28 )
69+ )
70+ }
71+ @ {
72+ Name = ' Braced member access with inline comment'
73+ ScriptDef = " `$ object. #comment`n {Prop}"
74+ ExpectedRanges = @ (
75+ , @ (18 , 24 )
76+ )
77+ }
78+ @ {
79+ Name = ' Braced member access with inner curly braces'
80+ ScriptDef = " `$ object.{{Prop}}"
81+ ExpectedRanges = @ (
82+ , @ (8 , 16 )
83+ )
84+ }
85+ @ {
86+ Name = ' Indexed Braced member access'
87+ ScriptDef = " `$ object[0].{Prop}"
88+ ExpectedRanges = @ (
89+ , @ (11 , 17 )
90+ )
91+ }
92+ @ {
93+ Name = ' Parenthesized Braced member access'
94+ ScriptDef = " (`$ object).{Prop}"
95+ ExpectedRanges = @ (
96+ , @ (10 , 16 )
97+ )
98+ }
99+ @ {
100+ Name = ' Chained Braced member access'
101+ ScriptDef = " `$ object.{Prop}.{InnerProp}"
102+ ExpectedRanges = @ (
103+ , @ (8 , 14 )
104+ , @ (15 , 26 )
105+ )
106+ }
107+ @ {
108+ Name = ' Multiple Braced member access in larger script'
109+ ScriptDef = @'
110+ $var = 1
111+ $a.prop.{{inner}}
112+ $a.{
113+ $a.{Prop}
114+ }
115+ '@
116+ ExpectedRanges = @ (
117+ , @ (17 , 26 )
118+ , @ (30 , 47 )
119+ )
120+ }
121+ )
122+ }
123+
124+ It ' Should correctly identify range for <Name>' - ForEach $RangeTests {
125+ $tokens = $null
126+ $parseErrors = $null
127+ $scriptAst = [System.Management.Automation.Language.Parser ]::ParseInput($ScriptDef , [ref ] $tokens , [ref ] $parseErrors )
128+ $tokenOperations = [Microsoft.Windows.PowerShell.ScriptAnalyzer.TokenOperations ]::new($tokens , $scriptAst )
129+ $ranges = $tokenOperations.GetBracedMemberAccessRanges ()
130+ $ranges.Count | Should - Be $ExpectedRanges.Count
131+ for ($i = 0 ; $i -lt $ranges.Count ; $i ++ ) {
132+ $ranges [$i ].Item1 | Should - Be $ExpectedRanges [$i ][0 ]
133+ $ranges [$i ].Item2 | Should - Be $ExpectedRanges [$i ][1 ]
134+ }
135+ }
136+
137+ It ' Should not identify dot-sourcing as braced member access' {
138+ $scriptText = @'
139+ . {5+5}
140+ $a=4;. {10+15}
141+ '@
142+ $tokens = $null
143+ $parseErrors = $null
144+ $scriptAst = [System.Management.Automation.Language.Parser ]::ParseInput($scriptText , [ref ] $tokens , [ref ] $parseErrors )
145+ $tokenOperations = [Microsoft.Windows.PowerShell.ScriptAnalyzer.TokenOperations ]::new($tokens , $scriptAst )
146+ $ranges = $tokenOperations.GetBracedMemberAccessRanges ()
147+ $ranges.Count | Should - Be 0
148+ }
149+
150+ It ' Should not return a range for an incomplete bracket pair (parse error)' {
151+ $scriptText = @'
152+ $object.{MemberName
153+ '@
154+ $tokens = $null
155+ $parseErrors = $null
156+ $scriptAst = [System.Management.Automation.Language.Parser ]::ParseInput($scriptText , [ref ] $tokens , [ref ] $parseErrors )
157+ $tokenOperations = [Microsoft.Windows.PowerShell.ScriptAnalyzer.TokenOperations ]::new($tokens , $scriptAst )
158+ $ranges = $tokenOperations.GetBracedMemberAccessRanges ()
159+ $ranges.Count | Should - Be 0
160+ }
161+
162+ It ' Should find the correct range for null-conditional braced member access' {
163+ $scriptText = ' $object?.{Prop}'
164+ $tokens = $null
165+ $parseErrors = $null
166+ $scriptAst = [System.Management.Automation.Language.Parser ]::ParseInput($scriptText , [ref ] $tokens , [ref ] $parseErrors )
167+ $tokenOperations = [Microsoft.Windows.PowerShell.ScriptAnalyzer.TokenOperations ]::new($tokens , $scriptAst )
168+ $ranges = $tokenOperations.GetBracedMemberAccessRanges ()
169+ $ranges.Count | Should - Be 1
170+ $ExpectedRanges = @ (
171+ , @ (9 , 15 )
172+ )
173+ for ($i = 0 ; $i -lt $ranges.Count ; $i ++ ) {
174+ $ranges [$i ].Item1 | Should - Be $ExpectedRanges [$i ][0 ]
175+ $ranges [$i ].Item2 | Should - Be $ExpectedRanges [$i ][1 ]
176+ }
177+ } - Skip:$ ($PSVersionTable.PSVersion.Major -lt 7 )
178+
179+ It ' Should find the correct range for nested null-conditional braced member access' {
180+ $scriptText = ' $object?.{Prop?.{InnerProp}}'
181+ $tokens = $null
182+ $parseErrors = $null
183+ $scriptAst = [System.Management.Automation.Language.Parser ]::ParseInput($scriptText , [ref ] $tokens , [ref ] $parseErrors )
184+ $tokenOperations = [Microsoft.Windows.PowerShell.ScriptAnalyzer.TokenOperations ]::new($tokens , $scriptAst )
185+ $ranges = $tokenOperations.GetBracedMemberAccessRanges ()
186+ $ranges.Count | Should - Be 1
187+ $ExpectedRanges = @ (
188+ , @ (9 , 28 )
189+ )
190+ for ($i = 0 ; $i -lt $ranges.Count ; $i ++ ) {
191+ $ranges [$i ].Item1 | Should - Be $ExpectedRanges [$i ][0 ]
192+ $ranges [$i ].Item2 | Should - Be $ExpectedRanges [$i ][1 ]
193+ }
194+ } - Skip:$ ($PSVersionTable.PSVersion.Major -lt 7 )
195+
196+ }
197+
21198}
0 commit comments