Skip to content

Commit

Permalink
test: add more object utils test + remove undefined value when use wi…
Browse files Browse the repository at this point in the history
…th invertKeysAndValues fnc (#4764)

### Description
Add filter `undefined/null` value when use with utils
**invertKeysAndValues** function
Add more test at `objects.test.ts`
<!--
What's included in this PR?
-->

### Drive-by changes
```diff
return Object.fromEntries(
    Object.entries(data)
+      .filter(([_, value]) => value !== undefined && value !== null) // Filter out undefined and null values
      .map(([key, value]) => [value, key]),
);
```
<!--
Are there any minor or drive-by changes also included?
-->

### Related issues
None
<!--
- Fixes #[issue number here]
-->

### Backward compatibility
Currently, nowhere call this **invertKeysAndValues** func
<!--
Are these changes backward compatible? Are there any infrastructure
implications, e.g. changes that would prohibit deploying older commits
using this infra tooling?

Yes/No
-->

### Testing
Yes, more tests.
<!--
What kind of testing have these changes undergone?

None/Manual/Unit Tests
-->

---------

Co-authored-by: J M Rossy <jm.rossy@gmail.com>
  • Loading branch information
tiendn and jmrossy authored Oct 28, 2024
1 parent e104cf6 commit 39a9b20
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/tidy-meals-add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hyperlane-xyz/utils": patch
---

Filter undefined/null values in invertKeysAndValues function
130 changes: 130 additions & 0 deletions typescript/utils/src/objects.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
import { expect } from 'chai';

import {
arrayToObject,
deepCopy,
deepEquals,
deepFind,
diffObjMerge,
invertKeysAndValues,
isObjEmpty,
isObject,
objFilter,
objKeys,
objLength,
objMap,
objMapEntries,
objMerge,
objOmit,
pick,
promiseObjAll,
stringifyObject,
} from './objects.js';

describe('Object utilities', () => {
Expand Down Expand Up @@ -83,6 +95,124 @@ describe('Object utilities', () => {
expect(isObject(42)).to.be.false;
});

it('objKeys', () => {
const obj = { a: 1, b: 2 };
expect(objKeys(obj)).to.eql(['a', 'b']);
});

it('objLength', () => {
const obj = { a: 1, b: 2 };
expect(objLength(obj)).to.equal(2);
});

it('isObjEmpty', () => {
expect(isObjEmpty({})).to.be.true;
expect(isObjEmpty({ a: 1 })).to.be.false;
});

it('objMapEntries', () => {
const obj = { a: 1, b: 2 };
const result = objMapEntries(obj, (k, v) => v * 2);
expect(result).to.eql([
['a', 2],
['b', 4],
]);
});

it('objMap', () => {
const obj = { a: 1, b: 2 };
const result = objMap(obj, (k, v) => v * 2);
expect(result).to.eql({ a: 2, b: 4 });
});

it('objFilter', () => {
const obj = { a: 1, b: 2, c: 3 };
const result = objFilter(obj, (k: string, v: number): v is number => v > 1);
expect(result).to.eql({ b: 2, c: 3 });
});

it('deepFind should find nested object', () => {
const obj = { a: { b: { c: 3 } } };
const result = deepFind(
obj,
(v: any): v is { c: number } => v && v.c === 3,
);
expect(result).to.eql({ c: 3 });
});

it('deepFind should return undefined if object is not found', () => {
const obj = { a: { b: { c: 3 } } };
const result = deepFind(
obj,
(v: any): v is { c: number } => v && v.c === 4,
);
expect(result).to.be.undefined;
});

it('promiseObjAll', async () => {
const obj = { a: Promise.resolve(1), b: Promise.resolve(2) };
const result = await promiseObjAll(obj);
expect(result).to.eql({ a: 1, b: 2 });
});

it('pick should return a subset of the object', () => {
const obj = { a: 1, b: 2, c: 3 };
const result = pick(obj, ['a', 'c']);
expect(result).to.eql({ a: 1, c: 3 });
});

it('pick should return an empty object if no keys are provided', () => {
const obj = { a: 1, b: 2, c: 3 };
const result = pick(obj, []);
expect(result).to.eql({});
});

it("pick should return an empty object if the object doesn't contain the keys", () => {
const obj = { c: 4, d: 5 };
const result = pick(obj as any, ['a', 'b']);
expect(result).to.eql({});
});

describe('invertKeysAndValues', () => {
it('invertKeysAndValues should invert the keys and values', () => {
const obj = { a: '1', b: '2' };
const result = invertKeysAndValues(obj);
expect(result).to.eql({ '1': 'a', '2': 'b' });
});

it('invertKeysAndValues should return an empty object if the object is empty', () => {
const obj = {};
const result = invertKeysAndValues(obj);
expect(result).to.eql({});
});

it('invertKeysAndValues should return an object if the object has duplicate values', () => {
const obj = { a: '1', b: '1' };
const result = invertKeysAndValues(obj);
expect(result).to.eql({ '1': 'b' });
});

it('invertKeysAndValues should return an object if the object has undefined/null values', () => {
const obj = { a: '1', b: '2', c: undefined, d: null, e: 0 };
const result = invertKeysAndValues(obj);
expect(result).to.eql({ '1': 'a', '2': 'b', '0': 'e' });
});
});

it('arrayToObject', () => {
const keys = ['a', 'b'];
const result = arrayToObject(keys);
expect(result).to.eql({ a: true, b: true });
});

it('stringifyObject', () => {
const obj = { a: 1, b: 2 };
const jsonResult = stringifyObject(obj, 'json');
expect(jsonResult).to.equal('{"a":1,"b":2}');
const yamlResult = stringifyObject(obj, 'yaml');
expect(yamlResult).to.include('a: 1\nb: 2');
});

describe('diffObjMerge', () => {
it('should merge objects with equal values', () => {
const actual = { a: 1, b: 2 };
Expand Down
4 changes: 3 additions & 1 deletion typescript/utils/src/objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,9 @@ export function objOmit<T extends Record<string, any> = any>(

export function invertKeysAndValues(data: any) {
return Object.fromEntries(
Object.entries(data).map(([key, value]) => [value, key]),
Object.entries(data)
.filter(([_, value]) => value !== undefined && value !== null) // Filter out undefined and null values
.map(([key, value]) => [value, key]),
);
}

Expand Down

0 comments on commit 39a9b20

Please sign in to comment.