Skip to content

Commit

Permalink
Add tests+fixes for string/number cases
Browse files Browse the repository at this point in the history
  • Loading branch information
Shaptic committed Jan 16, 2025
1 parent 2650f85 commit 9402f35
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 21 deletions.
36 changes: 19 additions & 17 deletions src/xdr.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,26 @@ import xdr from './generated/curr_generated';
import { scValToNative } from './scval';

xdr.scvMapSorted = (items) => {
return xdr.ScVal.scvMap(items.sort((a, b) => {
// Both a and b are `ScMapEntry`s, so we need to sort by underlying key.
//
// We couldn't possibly handle every combination of keys since Soroban
// maps don't enforce consistent types, so we do a best-effort and try
// sorting by "number-like" or "string-like."
let nativeA = scValToNative(a.key()),
nativeB = scValToNative(b.key());
let sorted = Array.from(items).sort((a, b) => {

Check warning on line 5 in src/xdr.js

View workflow job for this annotation

GitHub Actions / build

'sorted' is never reassigned. Use 'const' instead

Check warning on line 5 in src/xdr.js

View workflow job for this annotation

GitHub Actions / build

'sorted' is never reassigned. Use 'const' instead

Check warning on line 5 in src/xdr.js

View workflow job for this annotation

GitHub Actions / build (18)

'sorted' is never reassigned. Use 'const' instead

Check warning on line 5 in src/xdr.js

View workflow job for this annotation

GitHub Actions / build (20)

'sorted' is never reassigned. Use 'const' instead

Check warning on line 5 in src/xdr.js

View workflow job for this annotation

GitHub Actions / build (21)

'sorted' is never reassigned. Use 'const' instead
// Both a and b are `ScMapEntry`s, so we need to sort by underlying key.
//
// We couldn't possibly handle every combination of keys since Soroban
// maps don't enforce consistent types, so we do a best-effort and try
// sorting by "number-like" or "string-like."
let nativeA = scValToNative(a.key()),

Check warning on line 11 in src/xdr.js

View workflow job for this annotation

GitHub Actions / build

'nativeA' is never reassigned. Use 'const' instead

Check warning on line 11 in src/xdr.js

View workflow job for this annotation

GitHub Actions / build

'nativeA' is never reassigned. Use 'const' instead

Check warning on line 11 in src/xdr.js

View workflow job for this annotation

GitHub Actions / build (18)

'nativeA' is never reassigned. Use 'const' instead

Check warning on line 11 in src/xdr.js

View workflow job for this annotation

GitHub Actions / build (20)

'nativeA' is never reassigned. Use 'const' instead

Check warning on line 11 in src/xdr.js

View workflow job for this annotation

GitHub Actions / build (21)

'nativeA' is never reassigned. Use 'const' instead
nativeB = scValToNative(b.key());

Check warning on line 12 in src/xdr.js

View workflow job for this annotation

GitHub Actions / build

'nativeB' is never reassigned. Use 'const' instead

Check warning on line 12 in src/xdr.js

View workflow job for this annotation

GitHub Actions / build

'nativeB' is never reassigned. Use 'const' instead

Check warning on line 12 in src/xdr.js

View workflow job for this annotation

GitHub Actions / build (18)

'nativeB' is never reassigned. Use 'const' instead

Check warning on line 12 in src/xdr.js

View workflow job for this annotation

GitHub Actions / build (20)

'nativeB' is never reassigned. Use 'const' instead

Check warning on line 12 in src/xdr.js

View workflow job for this annotation

GitHub Actions / build (21)

'nativeB' is never reassigned. Use 'const' instead

switch (typeof nativeA) {
case "number":
case "bigint":
return nativeA < nativeB;
switch (typeof nativeA) {
case 'number':
case 'bigint':
return nativeA < nativeB ? -1 : 1;

default:
return nativeA.toString().localeCompare(nativeB.toString());
}
}));
}
default:
return nativeA.toString().localeCompare(nativeB.toString());
}
});

return xdr.ScVal.scvMap(sorted);
};

export default xdr;
73 changes: 69 additions & 4 deletions test/unit/scval_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@ describe('parsing and building ScVals', function () {
// iterate for granular errors on failures
targetScv.value().forEach((entry, idx) => {
const actual = scv.value()[idx];
// console.log(idx, 'exp:', JSON.stringify(entry));
// console.log(idx, 'act:', JSON.stringify(actual));
expect(entry).to.deep.equal(actual, `item ${idx} doesn't match`);
});

Expand Down Expand Up @@ -207,8 +205,8 @@ describe('parsing and building ScVals', function () {
);
});

it('throws on arrays with mixed types', function () {
expect(() => nativeToScVal([1, 'a', false])).to.throw(/same type/i);
it('doesnt throw on arrays with mixed types', function () {
expect(nativeToScVal([1, 'a', false]).switch().name).to.equal('scvVec');
});

it('lets strings be small integer ScVals', function () {
Expand Down Expand Up @@ -264,4 +262,71 @@ describe('parsing and building ScVals', function () {
}
]);
});

it('can sort maps by string', function () {
const sample = nativeToScVal(
{ a: 1, b: 2, c: 3 },
{
type: {
a: ['symbol'],
b: ['symbol'],
c: ['symbol']
}
}
);
['a', 'b', 'c'].forEach((val, idx) => {
expect(sample.value()[idx].key().value()).to.equal(val);
});

// nativeToScVal will sort, so we need to "unsort" to make sure it works.
// We'll do this by swapping 0 (a) and 2 (c).
let tmp = sample.value()[0];
sample.value()[0] = sample.value()[2];
sample.value()[2] = tmp;

['c', 'b', 'a'].forEach((val, idx) => {
expect(sample.value()[idx].key().value()).to.equal(val);
});

const sorted = xdr.scvMapSorted(sample.value());
expect(sorted.switch().name).to.equal('scvMap');
['a', 'b', 'c'].forEach((val, idx) => {
expect(sorted.value()[idx].key().value()).to.equal(val);
});
});

it('can sort number-like maps', function () {
const sample = nativeToScVal(
{ 1: 'a', 2: 'b', 3: 'c' },
{
type: {
1: ['i64', 'symbol'],
2: ['i64', 'symbol'],
3: ['i64', 'symbol']
}
}
);
expect(sample.value()[0].key().switch().name).to.equal('scvI64');

[1n, 2n, 3n].forEach((val, idx) => {
let underlyingKey = sample.value()[idx].key().value();
expect(underlyingKey.toBigInt()).to.equal(val);
});

// nativeToScVal will sort, so we need to "unsort" to make sure it works.
// We'll do this by swapping 0th (1n) and 2nd (3n).
let tmp = sample.value()[0];
sample.value()[0] = sample.value()[2];
sample.value()[2] = tmp;

[3n, 2n, 1n].forEach((val, idx) => {
expect(sample.value()[idx].key().value().toBigInt()).to.equal(val);
});

const sorted = xdr.scvMapSorted(sample.value());
expect(sorted.switch().name).to.equal('scvMap');
[1n, 2n, 3n].forEach((val, idx) => {
expect(sorted.value()[idx].key().value().toBigInt()).to.equal(val);
});
});
});

0 comments on commit 9402f35

Please sign in to comment.