@@ -1959,6 +1959,213 @@ function run_jsonlab_test(tests)
19591959 jd8{' flag' } = true ;
19601960 end
19611961 test_jsonlab(' test multiple attributes different types' , @savejson , {jd8{' dims' }, jd8{' units' }, jd8{' count' }, jd8{' flag' }}, ' [["time","space"],"meters",42,true]' , ' compact' , 1 );
1962+
1963+ fprintf(sprintf(' %s\n ' , char(ones(1 , 79 ) * 61 )));
1964+ fprintf(' Test jdict xarray-like coords\n ' );
1965+ fprintf(sprintf(' %s\n ' , char(ones(1 , 79 ) * 61 )));
1966+
1967+ % Test 1: Root level string coords selection
1968+ jd1 = jdict(reshape(1 : 12 , [3 , 4 ]));
1969+ if (exist(' OCTAVE_VERSION' , ' builtin' ) ~= 0 )
1970+ jd1 .setattr(' dims' , {' x' , ' y' });
1971+ jd1 .setattr(' coords' , struct(' x' , {{' a' , ' b' , ' c' }}, ' y' , {{' p' , ' q' , ' r' , ' s' }}));
1972+ else
1973+ jd1{' dims' } = {' x' , ' y' };
1974+ jd1{' coords' } = struct(' x' , {{' a' , ' b' , ' c' }}, ' y' , {{' p' , ' q' , ' r' , ' s' }});
1975+ end
1976+ test_jsonlab(' string coord single select x' , @savejson , jd1 .x(' b' ).v(), ' [2,5,8,11]' , ' compact' , 1 );
1977+ test_jsonlab(' string coord single select y' , @savejson , jd1 .y(' r' ).v(), ' [[7],[8],[9]]' , ' compact' , 1 );
1978+
1979+ % Test 2: Root level numeric coords selection
1980+ jd2 = jdict(reshape(1 : 12 , [3 , 4 ]));
1981+ if (exist(' OCTAVE_VERSION' , ' builtin' ) ~= 0 )
1982+ jd2 .setattr(' dims' , {' x' , ' y' });
1983+ jd2 .setattr(' coords' , struct(' x' , [10 , 20 , 30 ], ' y' , [100 , 200 , 300 , 400 ]));
1984+ else
1985+ jd2{' dims' } = {' x' , ' y' };
1986+ jd2{' coords' } = struct(' x' , [10 , 20 , 30 ], ' y' , [100 , 200 , 300 , 400 ]);
1987+ end
1988+ test_jsonlab(' numeric coord single select x' , @savejson , jd2 .x(20 ).v(), ' [2,5,8,11]' , ' compact' , 1 );
1989+ test_jsonlab(' numeric coord single select y' , @savejson , jd2 .y(300 ).v(), ' [[7],[8],[9]]' , ' compact' , 1 );
1990+
1991+ % Test 3: Multiple string coords selection
1992+ jd3 = jdict(reshape(1 : 12 , [3 , 4 ]));
1993+ if (exist(' OCTAVE_VERSION' , ' builtin' ) ~= 0 )
1994+ jd3 .setattr(' dims' , {' x' , ' y' });
1995+ jd3 .setattr(' coords' , struct(' x' , {{' a' , ' b' , ' c' }}, ' y' , {{' p' , ' q' , ' r' , ' s' }}));
1996+ else
1997+ jd3{' dims' } = {' x' , ' y' };
1998+ jd3{' coords' } = struct(' x' , {{' a' , ' b' , ' c' }}, ' y' , {{' p' , ' q' , ' r' , ' s' }});
1999+ end
2000+ test_jsonlab(' string coord multi select x' , @savejson , jd3 .x({' a' , ' c' }).v(), ' [[1,4,7,10],[3,6,9,12]]' , ' compact' , 1 );
2001+ test_jsonlab(' string coord multi select y' , @savejson , jd3 .y({' p' , ' s' }).v(), ' [[1,10],[2,11],[3,12]]' , ' compact' , 1 );
2002+
2003+ % Test 4: Multiple numeric coords selection
2004+ jd4 = jdict(reshape(1 : 12 , [3 , 4 ]));
2005+ if (exist(' OCTAVE_VERSION' , ' builtin' ) ~= 0 )
2006+ jd4 .setattr(' dims' , {' x' , ' y' });
2007+ jd4 .setattr(' coords' , struct(' x' , [10 , 20 , 30 ], ' y' , [100 , 200 , 300 , 400 ]));
2008+ else
2009+ jd4{' dims' } = {' x' , ' y' };
2010+ jd4{' coords' } = struct(' x' , [10 , 20 , 30 ], ' y' , [100 , 200 , 300 , 400 ]);
2011+ end
2012+ test_jsonlab(' numeric coord multi select x' , @savejson , jd4 .x([10 , 30 ]).v(), ' [[1,4,7,10],[3,6,9,12]]' , ' compact' , 1 );
2013+ test_jsonlab(' numeric coord multi select y' , @savejson , jd4 .y([100 , 400 ]).v(), ' [[1,10],[2,11],[3,12]]' , ' compact' , 1 );
2014+
2015+ % Test 5: Slice selection with struct
2016+ jd5 = jdict(reshape(1 : 12 , [3 , 4 ]));
2017+ if (exist(' OCTAVE_VERSION' , ' builtin' ) ~= 0 )
2018+ jd5 .setattr(' dims' , {' x' , ' y' });
2019+ jd5 .setattr(' coords' , struct(' x' , {{' a' , ' b' , ' c' }}, ' y' , {{' p' , ' q' , ' r' , ' s' }}));
2020+ else
2021+ jd5{' dims' } = {' x' , ' y' };
2022+ jd5{' coords' } = struct(' x' , {{' a' , ' b' , ' c' }}, ' y' , {{' p' , ' q' , ' r' , ' s' }});
2023+ end
2024+ test_jsonlab(' string coord slice x' , @savejson , jd5 .x(struct(' start' , ' a' , ' stop' , ' b' )).v(), ' [[1,4,7,10],[2,5,8,11]]' , ' compact' , 1 );
2025+ test_jsonlab(' string coord slice y' , @savejson , jd5 .y(struct(' start' , ' q' , ' stop' , ' s' )).v(), ' [[4,7,10],[5,8,11],[6,9,12]]' , ' compact' , 1 );
2026+
2027+ % Test 6: Second level coords
2028+ jd6 = jdict(struct(' data' , reshape(1 : 12 , [3 , 4 ])));
2029+ if (exist(' OCTAVE_VERSION' , ' builtin' ) ~= 0 )
2030+ jd6.(' data' ).setattr(' dims' , {' row' , ' col' });
2031+ jd6.(' data' ).setattr(' coords' , struct(' row' , {{' r1' , ' r2' , ' r3' }}, ' col' , [1 , 2 , 3 , 4 ]));
2032+ else
2033+ jd6.(' data' ){' dims' } = {' row' , ' col' };
2034+ jd6.(' data' ){' coords' } = struct(' row' , {{' r1' , ' r2' , ' r3' }}, ' col' , [1 , 2 , 3 , 4 ]);
2035+ end
2036+ test_jsonlab(' second level string coord' , @savejson , jd6.(' data' ).row(' r2' ).v(), ' [2,5,8,11]' , ' compact' , 1 );
2037+ test_jsonlab(' second level numeric coord' , @savejson , jd6.(' data' ).col(3 ).v(), ' [[7],[8],[9]]' , ' compact' , 1 );
2038+
2039+ % Test 7: Third level nested coords
2040+ jd7 = jdict(struct(' level1' , struct(' level2' , struct(' arr' , reshape(1 : 6 , [2 , 3 ])))));
2041+ if (exist(' OCTAVE_VERSION' , ' builtin' ) ~= 0 )
2042+ jd7.(' level1' ).(' level2' ).(' arr' ).setattr(' dims' , {' i' , ' j' });
2043+ jd7.(' level1' ).(' level2' ).(' arr' ).setattr(' coords' , struct(' i' , {{' x' , ' y' }}, ' j' , {{' a' , ' b' , ' c' }}));
2044+ else
2045+ jd7.(' level1' ).(' level2' ).(' arr' ){' dims' } = {' i' , ' j' };
2046+ jd7.(' level1' ).(' level2' ).(' arr' ){' coords' } = struct(' i' , {{' x' , ' y' }}, ' j' , {{' a' , ' b' , ' c' }});
2047+ end
2048+ test_jsonlab(' third level coord select i' , @savejson , jd7.(' level1' ).(' level2' ).(' arr' ).i(' y' ).v(), ' [2,4,6]' , ' compact' , 1 );
2049+ test_jsonlab(' third level coord select j' , @savejson , jd7.(' level1' ).(' level2' ).(' arr' ).j(' b' ).v(), ' [[3],[4]]' , ' compact' , 1 );
2050+
2051+ % Test 8: Sibling arrays with independent coords
2052+ jd8 = jdict(struct(' exp1' , reshape(1 : 6 , [2 , 3 ]), ' exp2' , reshape(1 : 8 , [2 , 4 ])));
2053+ if (exist(' OCTAVE_VERSION' , ' builtin' ) ~= 0 )
2054+ jd8.(' exp1' ).setattr(' dims' , {' t' , ' s' });
2055+ jd8.(' exp1' ).setattr(' coords' , struct(' t' , {{' t1' , ' t2' }}, ' s' , {{' s1' , ' s2' , ' s3' }}));
2056+ jd8.(' exp2' ).setattr(' dims' , {' x' , ' y' });
2057+ jd8.(' exp2' ).setattr(' coords' , struct(' x' , [0 , 1 ], ' y' , [10 , 20 , 30 , 40 ]));
2058+ else
2059+ jd8.(' exp1' ){' dims' } = {' t' , ' s' };
2060+ jd8.(' exp1' ){' coords' } = struct(' t' , {{' t1' , ' t2' }}, ' s' , {{' s1' , ' s2' , ' s3' }});
2061+ jd8.(' exp2' ){' dims' } = {' x' , ' y' };
2062+ jd8.(' exp2' ){' coords' } = struct(' x' , [0 , 1 ], ' y' , [10 , 20 , 30 , 40 ]);
2063+ end
2064+ test_jsonlab(' sibling coord select exp1' , @savejson , jd8.(' exp1' ).t(' t2' ).v(), ' [2,4,6]' , ' compact' , 1 );
2065+ test_jsonlab(' sibling coord select exp2' , @savejson , jd8.(' exp2' ).y(30 ).v(), ' [[5],[6]]' , ' compact' , 1 );
2066+
2067+ % Test 9: Direct index when coords defined (numeric index on string coords)
2068+ jd9 = jdict(reshape(1 : 12 , [3 , 4 ]));
2069+ if (exist(' OCTAVE_VERSION' , ' builtin' ) ~= 0 )
2070+ jd9 .setattr(' dims' , {' x' , ' y' });
2071+ jd9 .setattr(' coords' , struct(' x' , {{' a' , ' b' , ' c' }}, ' y' , {{' p' , ' q' , ' r' , ' s' }}));
2072+ else
2073+ jd9{' dims' } = {' x' , ' y' };
2074+ jd9{' coords' } = struct(' x' , {{' a' , ' b' , ' c' }}, ' y' , {{' p' , ' q' , ' r' , ' s' }});
2075+ end
2076+ test_jsonlab(' direct index with string coords' , @savejson , jd9 .x(2 ).v(), ' [2,5,8,11]' , ' compact' , 1 );
2077+
2078+ % Test 10: Coords without dims should not break indexing
2079+ jd10 = jdict(reshape(1 : 12 , [3 , 4 ]));
2080+ if (exist(' OCTAVE_VERSION' , ' builtin' ) ~= 0 )
2081+ jd10 .setattr(' dims' , {' x' , ' y' });
2082+ else
2083+ jd10{' dims' } = {' x' , ' y' };
2084+ end
2085+ test_jsonlab(' dims without coords still works' , @savejson , jd10 .x(2 ).v(), ' [2,5,8,11]' , ' compact' , 1 );
2086+
2087+ % Test 11: 3D array coords
2088+ jd11 = jdict(reshape(1 : 24 , [2 , 3 , 4 ]));
2089+ if (exist(' OCTAVE_VERSION' , ' builtin' ) ~= 0 )
2090+ jd11 .setattr(' dims' , {' x' , ' y' , ' z' });
2091+ jd11 .setattr(' coords' , struct(' x' , {{' a' , ' b' }}, ' y' , [10 , 20 , 30 ], ' z' , {{' p' , ' q' , ' r' , ' s' }}));
2092+ else
2093+ jd11{' dims' } = {' x' , ' y' , ' z' };
2094+ jd11{' coords' } = struct(' x' , {{' a' , ' b' }}, ' y' , [10 , 20 , 30 ], ' z' , {{' p' , ' q' , ' r' , ' s' }});
2095+ end
2096+ test_jsonlab(' 3D coord select dim1' , @savejson , jd11 .x(' b' ).v(), ' {"_ArrayType_":"double","_ArraySize_":[1,3,4],"_ArrayData_":[2,8,14,20,4,10,16,22,6,12,18,24]}' , ' compact' , 1 );
2097+ test_jsonlab(' 3D coord select dim2' , @savejson , jd11 .y(20 ).v(), ' {"_ArrayType_":"double","_ArraySize_":[2,1,4],"_ArrayData_":[3,9,15,21,4,10,16,22]}' , ' compact' , 1 );
2098+ test_jsonlab(' 3D coord select dim3' , @savejson , jd11 .z(' r' ).v(), ' [[13,15,17],[14,16,18]]' , ' compact' , 1 );
2099+
2100+ % Test 12: getattr returns coords correctly
2101+ jd12 = jdict(rand(3 , 4 ));
2102+ if (exist(' OCTAVE_VERSION' , ' builtin' ) ~= 0 )
2103+ jd12 .setattr(' dims' , {' x' , ' y' });
2104+ jd12 .setattr(' coords' , struct(' x' , {{' a' , ' b' , ' c' }}, ' y' , [1 , 2 , 3 , 4 ]));
2105+ else
2106+ jd12{' dims' } = {' x' , ' y' };
2107+ jd12{' coords' } = struct(' x' , {{' a' , ' b' , ' c' }}, ' y' , [1 , 2 , 3 , 4 ]);
2108+ end
2109+ test_jsonlab(' getattr returns coords struct' , @savejson , jd12{' coords' }, ' {"x":["a","b","c"],"y":[1,2,3,4]}' , ' compact' , 1 );
2110+
2111+ % Test 13: Cascade two single selections
2112+ jd13 = jdict(reshape(1 : 12 , [3 , 4 ]));
2113+ if (exist(' OCTAVE_VERSION' , ' builtin' ) ~= 0 )
2114+ jd13 .setattr(' dims' , {' x' , ' y' });
2115+ jd13 .setattr(' coords' , struct(' x' , {{' a' , ' b' , ' c' }}, ' y' , {{' p' , ' q' , ' r' , ' s' }}));
2116+ else
2117+ jd13{' dims' } = {' x' , ' y' };
2118+ jd13{' coords' } = struct(' x' , {{' a' , ' b' , ' c' }}, ' y' , {{' p' , ' q' , ' r' , ' s' }});
2119+ end
2120+ test_jsonlab(' cascade x then y' , @savejson , jd13 .x(' b' ).y(' r' ).v(), ' [8]' , ' compact' , 1 );
2121+ test_jsonlab(' cascade y then x' , @savejson , jd13 .y(' q' ).x(' c' ).v(), ' [6]' , ' compact' , 1 );
2122+
2123+ % Test 14: Cascade multi-select then single
2124+ jd14 = jdict(reshape(1 : 12 , [3 , 4 ]));
2125+ if (exist(' OCTAVE_VERSION' , ' builtin' ) ~= 0 )
2126+ jd14 .setattr(' dims' , {' x' , ' y' });
2127+ jd14 .setattr(' coords' , struct(' x' , {{' a' , ' b' , ' c' }}, ' y' , {{' p' , ' q' , ' r' , ' s' }}));
2128+ else
2129+ jd14{' dims' } = {' x' , ' y' };
2130+ jd14{' coords' } = struct(' x' , {{' a' , ' b' , ' c' }}, ' y' , {{' p' , ' q' , ' r' , ' s' }});
2131+ end
2132+ test_jsonlab(' cascade multi then single' , @savejson , jd14 .x({' a' , ' c' }).y(' s' ).v(), ' [[10],[12]]' , ' compact' , 1 );
2133+ test_jsonlab(' cascade single then multi' , @savejson , jd14 .y(' p' ).x({' a' , ' b' }).v(), ' [[1],[2]]' , ' compact' , 1 );
2134+
2135+ % Test 15: Cascade with numeric coords
2136+ jd15 = jdict(reshape(1 : 12 , [3 , 4 ]));
2137+ if (exist(' OCTAVE_VERSION' , ' builtin' ) ~= 0 )
2138+ jd15 .setattr(' dims' , {' x' , ' y' });
2139+ jd15 .setattr(' coords' , struct(' x' , [10 , 20 , 30 ], ' y' , [100 , 200 , 300 , 400 ]));
2140+ else
2141+ jd15{' dims' } = {' x' , ' y' };
2142+ jd15{' coords' } = struct(' x' , [10 , 20 , 30 ], ' y' , [100 , 200 , 300 , 400 ]);
2143+ end
2144+ test_jsonlab(' cascade numeric coords' , @savejson , jd15 .x(20 ).y(300 ).v(), ' [8]' , ' compact' , 1 );
2145+ test_jsonlab(' cascade numeric multi then single' , @savejson , jd15 .x([10 , 30 ]).y(400 ).v(), ' [[10],[12]]' , ' compact' , 1 );
2146+
2147+ % Test 16: Cascade in nested struct
2148+ jd16 = jdict(struct(' data' , reshape(1 : 12 , [3 , 4 ])));
2149+ if (exist(' OCTAVE_VERSION' , ' builtin' ) ~= 0 )
2150+ jd16.(' data' ).setattr(' dims' , {' row' , ' col' });
2151+ jd16.(' data' ).setattr(' coords' , struct(' row' , {{' r1' , ' r2' , ' r3' }}, ' col' , {{' c1' , ' c2' , ' c3' , ' c4' }}));
2152+ else
2153+ jd16.(' data' ){' dims' } = {' row' , ' col' };
2154+ jd16.(' data' ){' coords' } = struct(' row' , {{' r1' , ' r2' , ' r3' }}, ' col' , {{' c1' , ' c2' , ' c3' , ' c4' }});
2155+ end
2156+ test_jsonlab(' cascade in nested struct' , @savejson , jd16.(' data' ).row(' r2' ).col(' c3' ).v(), ' [8]' , ' compact' , 1 );
2157+
2158+ % Test 17: Cascade on 3D array
2159+ jd17 = jdict(reshape(1 : 24 , [2 , 3 , 4 ]));
2160+ if (exist(' OCTAVE_VERSION' , ' builtin' ) ~= 0 )
2161+ jd17 .setattr(' dims' , {' x' , ' y' , ' z' });
2162+ jd17 .setattr(' coords' , struct(' x' , {{' a' , ' b' }}, ' y' , {{' p' , ' q' , ' r' }}, ' z' , {{' i' , ' j' , ' k' , ' l' }}));
2163+ else
2164+ jd17{' dims' } = {' x' , ' y' , ' z' };
2165+ jd17{' coords' } = struct(' x' , {{' a' , ' b' }}, ' y' , {{' p' , ' q' , ' r' }}, ' z' , {{' i' , ' j' , ' k' , ' l' }});
2166+ end
2167+ test_jsonlab(' 3D cascade two dims' , @savejson , jd17 .x(' b' ).z(' k' ).v(), ' [14,16,18]' , ' compact' , 1 );
2168+ test_jsonlab(' 3D cascade all three dims' , @savejson , jd17 .x(' a' ).y(' q' ).z(' j' ).v(), ' [9]' , ' compact' , 1 );
19622169end
19632170
19642171%%
0 commit comments