@@ -2116,4 +2116,376 @@ public void TryGetValue_WithInvalidBracketKey_ReturnsFalse()
21162116 }
21172117
21182118 #endregion
2119+
2120+ #region Dictionary with Numeric String Keys Tests (GitHub Issue #1)
2121+
2122+ public class DictionaryNumericKeyTests
2123+ {
2124+ [ Fact ]
2125+ public void GetValue_DictionaryStringString_WithNumericKey_ReturnsValue ( )
2126+ {
2127+ // Arrange - Exact case from GitHub issue #1
2128+ var dict = new Dictionary < string , string >
2129+ {
2130+ [ "1" ] = "hello world"
2131+ } ;
2132+
2133+ // Act
2134+ var result = ObjectPath . GetValue ( dict , "[1]" ) ;
2135+
2136+ // Assert
2137+ Assert . Equal ( "hello world" , result ) ;
2138+ }
2139+
2140+ [ Fact ]
2141+ public void GetValue_DictionaryStringObject_WithNumericKey_ReturnsValue ( )
2142+ {
2143+ // Arrange
2144+ var dict = new Dictionary < string , object >
2145+ {
2146+ [ "0" ] = "zero" ,
2147+ [ "1" ] = "one" ,
2148+ [ "2" ] = "two"
2149+ } ;
2150+
2151+ // Act & Assert
2152+ Assert . Equal ( "zero" , ObjectPath . GetValue ( dict , "[0]" ) ) ;
2153+ Assert . Equal ( "one" , ObjectPath . GetValue ( dict , "[1]" ) ) ;
2154+ Assert . Equal ( "two" , ObjectPath . GetValue ( dict , "[2]" ) ) ;
2155+ }
2156+
2157+ [ Fact ]
2158+ public void GetValue_DictionaryStringInt_WithNumericKey_ReturnsValue ( )
2159+ {
2160+ // Arrange
2161+ var dict = new Dictionary < string , int >
2162+ {
2163+ [ "100" ] = 999 ,
2164+ [ "200" ] = 888
2165+ } ;
2166+
2167+ // Act
2168+ var result = ObjectPath . GetValue ( dict , "[100]" ) ;
2169+
2170+ // Assert
2171+ Assert . Equal ( 999 , result ) ;
2172+ }
2173+
2174+ [ Fact ]
2175+ public void GetValue_Hashtable_WithNumericStringKey_ReturnsValue ( )
2176+ {
2177+ // Arrange
2178+ var hashtable = new System . Collections . Hashtable
2179+ {
2180+ [ "1" ] = "hashtable value" ,
2181+ [ "2" ] = 42
2182+ } ;
2183+
2184+ // Act
2185+ var result1 = ObjectPath . GetValue ( hashtable , "[1]" ) ;
2186+ var result2 = ObjectPath . GetValue ( hashtable , "[2]" ) ;
2187+
2188+ // Assert
2189+ Assert . Equal ( "hashtable value" , result1 ) ;
2190+ Assert . Equal ( 42 , result2 ) ;
2191+ }
2192+
2193+ [ Fact ]
2194+ public void GetValue_NestedDictionary_WithNumericKeys_ReturnsValue ( )
2195+ {
2196+ // Arrange
2197+ var dict = new Dictionary < string , object >
2198+ {
2199+ [ "1" ] = new Dictionary < string , object >
2200+ {
2201+ [ "2" ] = new Dictionary < string , string >
2202+ {
2203+ [ "3" ] = "nested value"
2204+ }
2205+ }
2206+ } ;
2207+
2208+ // Act
2209+ var result = ObjectPath . GetValue ( dict , "[1][2][3]" ) ;
2210+
2211+ // Assert
2212+ Assert . Equal ( "nested value" , result ) ;
2213+ }
2214+
2215+ [ Fact ]
2216+ public void GetValue_DictionaryWithArrayValue_NumericKeyThenArrayIndex ( )
2217+ {
2218+ // Arrange - Dictionary with numeric key containing an array
2219+ var dict = new Dictionary < string , object >
2220+ {
2221+ [ "1" ] = new [ ] { "a" , "b" , "c" }
2222+ } ;
2223+
2224+ // Act - Access dictionary key "1", then array index 2
2225+ var result = ObjectPath . GetValue ( dict , "[1][2]" ) ;
2226+
2227+ // Assert
2228+ Assert . Equal ( "c" , result ) ;
2229+ }
2230+
2231+ [ Fact ]
2232+ public void GetValue_ArrayContainingDictionaryWithNumericKey_WorksCorrectly ( )
2233+ {
2234+ // Arrange - Array containing dictionaries with numeric keys
2235+ var array = new object [ ]
2236+ {
2237+ new Dictionary < string , string > { [ "0" ] = "dict0-key0" } ,
2238+ new Dictionary < string , string > { [ "1" ] = "dict1-key1" }
2239+ } ;
2240+
2241+ // Act - Access array index 0, then dictionary key "0"
2242+ var result0 = ObjectPath . GetValue ( array , "[0][0]" ) ;
2243+ var result1 = ObjectPath . GetValue ( array , "[1][1]" ) ;
2244+
2245+ // Assert
2246+ Assert . Equal ( "dict0-key0" , result0 ) ;
2247+ Assert . Equal ( "dict1-key1" , result1 ) ;
2248+ }
2249+
2250+ [ Fact ]
2251+ public void GetValue_DictionaryNumericKey_WithDotNotation_ReturnsNestedValue ( )
2252+ {
2253+ // Arrange
2254+ var dict = new Dictionary < string , object >
2255+ {
2256+ [ "1" ] = new { Name = "Test" , Value = 123 }
2257+ } ;
2258+
2259+ // Act
2260+ var name = ObjectPath . GetValue ( dict , "[1].Name" ) ;
2261+ var value = ObjectPath . GetValue ( dict , "[1].Value" ) ;
2262+
2263+ // Assert
2264+ Assert . Equal ( "Test" , name ) ;
2265+ Assert . Equal ( 123 , value ) ;
2266+ }
2267+
2268+ [ Fact ]
2269+ public void GetValue_DictionaryNumericKey_CaseInsensitive_NotApplicable ( )
2270+ {
2271+ // Arrange - Numeric keys are exact match only (case sensitivity doesn't apply)
2272+ var dict = new Dictionary < string , string >
2273+ {
2274+ [ "1" ] = "value"
2275+ } ;
2276+
2277+ // Act & Assert - Both ignoreCase true and false should work
2278+ Assert . Equal ( "value" , ObjectPath . GetValue ( dict , "[1]" , ignoreCase : true ) ) ;
2279+ Assert . Equal ( "value" , ObjectPath . GetValue ( dict , "[1]" , ignoreCase : false ) ) ;
2280+ }
2281+
2282+ [ Fact ]
2283+ public void TryGetValue_DictionaryNumericKey_ReturnsTrue ( )
2284+ {
2285+ // Arrange
2286+ var dict = new Dictionary < string , string >
2287+ {
2288+ [ "1" ] = "hello"
2289+ } ;
2290+
2291+ // Act
2292+ var result = ObjectPath . TryGetValue ( dict , "[1]" , out var value ) ;
2293+
2294+ // Assert
2295+ Assert . True ( result ) ;
2296+ Assert . Equal ( "hello" , value ) ;
2297+ }
2298+
2299+ [ Fact ]
2300+ public void TryGetValue_DictionaryNumericKey_Generic_ReturnsTrue ( )
2301+ {
2302+ // Arrange
2303+ var dict = new Dictionary < string , int >
2304+ {
2305+ [ "42" ] = 100
2306+ } ;
2307+
2308+ // Act
2309+ var result = ObjectPath . TryGetValue < int > ( dict , "[42]" , out var value ) ;
2310+
2311+ // Assert
2312+ Assert . True ( result ) ;
2313+ Assert . Equal ( 100 , value ) ;
2314+ }
2315+
2316+ [ Fact ]
2317+ public void GetValue_DictionaryNumericKey_KeyNotFound_ThrowsException ( )
2318+ {
2319+ // Arrange
2320+ var dict = new Dictionary < string , string >
2321+ {
2322+ [ "1" ] = "value"
2323+ } ;
2324+
2325+ // Act & Assert - Key "99" doesn't exist, and there's no array to index
2326+ var ex = Assert . Throws < InvalidObjectPathException > ( ( ) => ObjectPath . GetValue ( dict , "[99]" ) ) ;
2327+ Assert . Contains ( "99" , ex . Message ) ;
2328+ }
2329+
2330+ [ Fact ]
2331+ public void GetValue_ArrayAccess_StillWorksAfterDictionaryFix ( )
2332+ {
2333+ // Arrange - Ensure regular array access is not broken
2334+ var obj = new
2335+ {
2336+ Items = new [ ] { "first" , "second" , "third" }
2337+ } ;
2338+
2339+ // Act
2340+ var result = ObjectPath . GetValue ( obj , "Items[1]" ) ;
2341+
2342+ // Assert
2343+ Assert . Equal ( "second" , result ) ;
2344+ }
2345+
2346+ [ Fact ]
2347+ public void GetValue_ListAccess_StillWorksAfterDictionaryFix ( )
2348+ {
2349+ // Arrange - Ensure list access is not broken
2350+ var obj = new
2351+ {
2352+ Numbers = new List < int > { 10 , 20 , 30 , 40 , 50 }
2353+ } ;
2354+
2355+ // Act
2356+ var result = ObjectPath . GetValue ( obj , "Numbers[3]" ) ;
2357+
2358+ // Assert
2359+ Assert . Equal ( 40 , result ) ;
2360+ }
2361+
2362+ [ Fact ]
2363+ public void GetValue_MixedDictionaryAndArray_ComplexPath ( )
2364+ {
2365+ // Arrange - Complex structure with both dictionaries and arrays
2366+ var data = new Dictionary < string , object >
2367+ {
2368+ [ "users" ] = new [ ]
2369+ {
2370+ new Dictionary < string , object >
2371+ {
2372+ [ "1" ] = new { Name = "Alice" }
2373+ } ,
2374+ new Dictionary < string , object >
2375+ {
2376+ [ "2" ] = new { Name = "Bob" }
2377+ }
2378+ }
2379+ } ;
2380+
2381+ // Act - users[0] = array index, [1] = dictionary key
2382+ var alice = ObjectPath . GetValue ( data , "users[0][1].Name" ) ;
2383+ var bob = ObjectPath . GetValue ( data , "users[1][2].Name" ) ;
2384+
2385+ // Assert
2386+ Assert . Equal ( "Alice" , alice ) ;
2387+ Assert . Equal ( "Bob" , bob ) ;
2388+ }
2389+
2390+ [ Fact ]
2391+ public void GetValue_DictionaryNumericKey_VsStringLiteralSyntax_SameResult ( )
2392+ {
2393+ // Arrange
2394+ var dict = new Dictionary < string , string >
2395+ {
2396+ [ "1" ] = "value"
2397+ } ;
2398+
2399+ // Act - Both syntaxes should work
2400+ var resultBracket = ObjectPath . GetValue ( dict , "[1]" ) ;
2401+ var resultStringLiteral = ObjectPath . GetValue ( dict , "[\" 1\" ]" ) ;
2402+
2403+ // Assert
2404+ Assert . Equal ( "value" , resultBracket ) ;
2405+ Assert . Equal ( "value" , resultStringLiteral ) ;
2406+ Assert . Equal ( resultBracket , resultStringLiteral ) ;
2407+ }
2408+
2409+ [ Fact ]
2410+ public void GetValue_EmptyDictionary_NumericKey_ThrowsException ( )
2411+ {
2412+ // Arrange
2413+ var dict = new Dictionary < string , string > ( ) ;
2414+
2415+ // Act & Assert
2416+ Assert . Throws < InvalidObjectPathException > ( ( ) => ObjectPath . GetValue ( dict , "[0]" ) ) ;
2417+ }
2418+
2419+ [ Fact ]
2420+ public void GetValue_DictionaryWithNegativeNumericKey_ReturnsValue ( )
2421+ {
2422+ // Arrange - Dictionary can have negative number as string key
2423+ var dict = new Dictionary < string , string >
2424+ {
2425+ [ "-1" ] = "negative one"
2426+ } ;
2427+
2428+ // Act
2429+ var result = ObjectPath . GetValue ( dict , "[-1]" ) ;
2430+
2431+ // Assert
2432+ Assert . Equal ( "negative one" , result ) ;
2433+ }
2434+
2435+ [ Fact ]
2436+ public void GetValue_DictionaryWithLeadingZeroKey_ReturnsValue ( )
2437+ {
2438+ // Arrange - Dictionary key "01" is different from "1"
2439+ var dict = new Dictionary < string , string >
2440+ {
2441+ [ "01" ] = "zero-one" ,
2442+ [ "1" ] = "one"
2443+ } ;
2444+
2445+ // Act
2446+ var result01 = ObjectPath . GetValue ( dict , "[01]" ) ;
2447+ var result1 = ObjectPath . GetValue ( dict , "[1]" ) ;
2448+
2449+ // Assert - Dictionary lookup uses the exact segment string
2450+ // "[01]" segment is "01" -> matches key "01"
2451+ // "[1]" segment is "1" -> matches key "1"
2452+ Assert . Equal ( "zero-one" , result01 ) ;
2453+ Assert . Equal ( "one" , result1 ) ;
2454+ }
2455+
2456+ [ Fact ]
2457+ public void GetValueByPath_ExtensionMethod_DictionaryNumericKey_Works ( )
2458+ {
2459+ // Arrange
2460+ var dict = new Dictionary < string , string >
2461+ {
2462+ [ "1" ] = "extension test"
2463+ } ;
2464+
2465+ // Act
2466+ var result = dict . GetValueByPath ( "[1]" ) ;
2467+
2468+ // Assert
2469+ Assert . Equal ( "extension test" , result ) ;
2470+ }
2471+
2472+ [ Fact ]
2473+ public void TryGetValueByPath_ExtensionMethod_DictionaryNumericKey_Works ( )
2474+ {
2475+ // Arrange
2476+ var dict = new Dictionary < string , string >
2477+ {
2478+ [ "1" ] = "extension test"
2479+ } ;
2480+
2481+ // Act
2482+ var success = dict . TryGetValueByPath ( "[1]" , out var result ) ;
2483+
2484+ // Assert
2485+ Assert . True ( success ) ;
2486+ Assert . Equal ( "extension test" , result ) ;
2487+ }
2488+ }
2489+
2490+ #endregion
21192491}
0 commit comments