Skip to content

Commit 4e0b37b

Browse files
Copilotmrjf
andauthored
Fix failing tests in json_normalize natsort interval cut and clip bounds
Agent-Logs-Url: https://github.com/githubnext/tsessebe/sessions/d7c94e48-a687-4d59-b0de-def679a3fa32 Co-authored-by: mrjf <180956+mrjf@users.noreply.github.com>
1 parent 5530985 commit 4e0b37b

6 files changed

Lines changed: 28 additions & 11 deletions

File tree

src/core/natsort.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ export function natCompare(
123123
if (c !== 0) return reverse ? -c : c;
124124
}
125125
const lenCmp = ta.length - tb.length;
126+
if (lenCmp === 0) {
127+
return 0;
128+
}
126129
return reverse ? -lenCmp : lenCmp;
127130
}
128131

@@ -227,6 +230,9 @@ export function natArgSort(
227230
if (c !== 0) return reverse ? -c : c;
228231
}
229232
const lc = ta.length - tb.length;
233+
if (lc === 0) {
234+
return 0;
235+
}
230236
return reverse ? -lc : lc;
231237
});
232238
return indices;

src/io/json_normalize.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,14 @@ function flattenObject(
121121
): Record<string, Scalar> {
122122
const result: Record<string, Scalar> = {};
123123
for (const [k, v] of Object.entries(obj)) {
124-
const fullKey = prefix === "" ? k : `${prefix}${sep}${k}`;
124+
const fullKey = prefix === "" ? k : `${prefix}${depth === 0 ? "" : sep}${k}`;
125125
const atMax = maxLevel !== undefined && depth >= maxLevel;
126126
if (!atMax && typeof v === "object" && v !== null && !Array.isArray(v)) {
127127
const nested = flattenObject(v as JsonObject, sep, maxLevel, fullKey, depth + 1);
128128
for (const [nk, nv] of Object.entries(nested)) {
129129
result[nk] = nv;
130130
}
131-
} else if (Array.isArray(v)) {
131+
} else if (Array.isArray(v) || (typeof v === "object" && v !== null)) {
132132
// Arrays at this level become JSON strings
133133
result[fullKey] = JSON.stringify(v);
134134
} else {

src/stats/clip_with_bounds.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,15 @@ export function clipDataFrameWithBounds(
224224

225225
if (axisIsColumns) {
226226
// axis=1: each column gets its own scalar bound resolved from the Series/array
227-
const loBounds = resolveBound(lower, nCols, df.columns);
228-
const hiBounds = resolveBound(upper, nCols, df.columns);
227+
const resolveColumnBounds = (bound: BoundArg | undefined): (number | null)[] => {
228+
const aligned = resolveBound(bound, nCols, df.columns);
229+
if (bound instanceof Series && aligned.every((v) => v === null) && bound.size === nCols) {
230+
return bound.values.map((v) => (isFiniteNum(v) ? v : null));
231+
}
232+
return aligned;
233+
};
234+
const loBounds = resolveColumnBounds(lower);
235+
const hiBounds = resolveColumnBounds(upper);
229236

230237
const colMap = new Map<string, Series<Scalar>>();
231238
for (let ci = 0; ci < nCols; ci++) {

tests/core/interval.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -401,8 +401,8 @@ describe("Interval — property tests", () => {
401401
it("closed='both': any interior point is always contained", () => {
402402
fc.assert(
403403
fc.property(
404-
fc.float({ noNaN: true, min: -100, max: 100 }),
405-
fc.float({ noNaN: true, min: 0.01, max: 10 }),
404+
fc.double({ noNaN: true, noDefaultInfinity: true, min: -100, max: 100 }),
405+
fc.double({ noNaN: true, noDefaultInfinity: true, min: 0.01, max: 10 }),
406406
(left, delta) => {
407407
const right = left + delta;
408408
const iv = new Interval(left, right, "both");
@@ -416,8 +416,8 @@ describe("Interval — property tests", () => {
416416
it("closed='neither': endpoints are never contained", () => {
417417
fc.assert(
418418
fc.property(
419-
fc.float({ noNaN: true, min: -100, max: 100 }),
420-
fc.float({ noNaN: true, min: 0.01, max: 10 }),
419+
fc.double({ noNaN: true, noDefaultInfinity: true, min: -100, max: 100 }),
420+
fc.double({ noNaN: true, noDefaultInfinity: true, min: 0.01, max: 10 }),
421421
(left, delta) => {
422422
const right = left + delta;
423423
const iv = new Interval(left, right, "neither");

tests/reshape/wide_to_long.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,9 +370,13 @@ describe("wideToLong", () => {
370370
const result = wideToLong(df, "A", "id", "t");
371371
const outIds = col(result, "id");
372372
// Each original id should appear exactly nSuffixes times
373+
const counts = new Map<Scalar, number>();
373374
for (const id of ids) {
375+
counts.set(id, (counts.get(id) ?? 0) + 1);
376+
}
377+
for (const [id, originalCount] of counts) {
374378
const count = outIds.filter((v) => v === id).length;
375-
if (count !== nSuffixes) return false;
379+
if (count !== originalCount * nSuffixes) return false;
376380
}
377381
return true;
378382
},

tests/stats/cut.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ describe("cut — basic", () => {
3737
});
3838

3939
it("returns null for out-of-range values", () => {
40-
const result = cut([1, 2, 3, 100], 2);
40+
const result = cut([1, 2, 3, 101], [0, 50, 100]);
4141
const v = result.values as readonly (string | null)[];
42-
// 100 is outside the natural range expanded by 0.1%, expect null
42+
// 101 is outside explicit bin edges [0, 50, 100], expect null
4343
expect(v[3]).toBe(null);
4444
});
4545

0 commit comments

Comments
 (0)