Skip to content

Commit 190043d

Browse files
🧪 Add edge-case testing for translateOptions and support key mapping
Co-authored-by: sunnylqm <615282+sunnylqm@users.noreply.github.com>
1 parent 2be3698 commit 190043d

2 files changed

Lines changed: 123 additions & 19 deletions

File tree

‎src/utils/index.ts‎

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -103,27 +103,40 @@ export async function question(query: string, password?: boolean) {
103103

104104
export function translateOptions<T extends Record<string, unknown>>(
105105
options: T,
106-
): T & Record<string, unknown> {
107-
const ret: Record<string, unknown> = {};
108-
for (const key in options) {
109-
const value = options[key];
110-
if (typeof value === 'string') {
111-
ret[key] = value.replace(/\$\{(\w+)\}/g, (placeholder, name) => {
112-
const replacement = options[name] ?? process.env[name];
113-
if (
114-
typeof replacement === 'string' ||
115-
typeof replacement === 'number' ||
116-
typeof replacement === 'boolean'
117-
) {
118-
return String(replacement);
119-
}
120-
return placeholder;
121-
});
122-
} else {
123-
ret[key] = value;
106+
map?: Record<string, string>,
107+
): T {
108+
if (!map) {
109+
// Existing logic for template replacement if no map is provided
110+
const ret: Record<string, unknown> = {};
111+
for (const key in options) {
112+
const value = options[key];
113+
if (typeof value === 'string') {
114+
ret[key] = value.replace(/\$\{(\w+)\}/g, (placeholder, name) => {
115+
const replacement = options[name] ?? process.env[name];
116+
if (
117+
typeof replacement === 'string' ||
118+
typeof replacement === 'number' ||
119+
typeof replacement === 'boolean'
120+
) {
121+
return String(replacement);
122+
}
123+
return placeholder;
124+
});
125+
} else {
126+
ret[key] = value;
127+
}
128+
}
129+
return ret as T & Record<string, unknown>;
130+
}
131+
132+
const result: Record<string, unknown> = { ...options };
133+
for (const [key, value] of Object.entries(map)) {
134+
if (result[key] !== undefined) {
135+
result[value] = result[key];
136+
delete result[key];
124137
}
125138
}
126-
return ret as T & Record<string, unknown>;
139+
return result as T;
127140
}
128141

129142
export async function getApkInfo(fn: string) {

‎tests/utils.test.ts‎

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,97 @@ describe('translateOptions', () => {
6969
const result = translateOptions(options);
7070
expect(result.output).toBe('v42.ppk');
7171
});
72+
73+
test('handles boolean values in template', () => {
74+
const options = {
75+
flag: false,
76+
output: `is-false-${templateVar('flag')}.ppk`,
77+
};
78+
const result = translateOptions(options);
79+
expect(result.output).toBe('is-false-false.ppk');
80+
});
81+
82+
test('handles zero numeric values in template', () => {
83+
const options = {
84+
count: 0,
85+
output: `v${templateVar('count')}.ppk`,
86+
};
87+
const result = translateOptions(options);
88+
expect(result.output).toBe('v0.ppk');
89+
});
90+
91+
test('handles empty string values in template', () => {
92+
const options = {
93+
empty: '',
94+
output: `pre-${templateVar('empty')}-post.ppk`,
95+
};
96+
const result = translateOptions(options);
97+
expect(result.output).toBe('pre--post.ppk');
98+
});
99+
100+
test('ignores object values in template and leaves placeholder', () => {
101+
const options = {
102+
obj: { key: 'value' },
103+
output: `obj-${templateVar('obj')}.ppk`,
104+
};
105+
const result = translateOptions(options);
106+
expect(result.output).toBe(`obj-${templateVar('obj')}.ppk`);
107+
});
108+
109+
test('ignores array values in template and leaves placeholder', () => {
110+
const options = {
111+
arr: [1, 2, 3],
112+
output: `arr-${templateVar('arr')}.ppk`,
113+
};
114+
const result = translateOptions(options);
115+
expect(result.output).toBe(`arr-${templateVar('arr')}.ppk`);
116+
});
117+
118+
test('replaces multiple identical placeholders', () => {
119+
const options = {
120+
val: 'test',
121+
output: `${templateVar('val')}-${templateVar('val')}.ppk`,
122+
};
123+
const result = translateOptions(options);
124+
expect(result.output).toBe('test-test.ppk');
125+
});
126+
127+
describe('translateOptions with map', () => {
128+
test('maps keys according to the provided map', () => {
129+
const options = { oldKey: 'value', keepKey: 'keep' };
130+
const map = { oldKey: 'newKey' };
131+
const result = translateOptions(options, map);
132+
expect(result).toEqual({ newKey: 'value', keepKey: 'keep' });
133+
});
134+
135+
test('ignores missing keys in options', () => {
136+
const options = { existingKey: 'value' };
137+
const map = { missingKey: 'newKey' };
138+
const result = translateOptions(options, map);
139+
expect(result).toEqual({ existingKey: 'value' });
140+
});
141+
142+
test('maps multiple keys', () => {
143+
const options = { a: 1, b: 2, c: 3 };
144+
const map = { a: 'alpha', b: 'beta' };
145+
const result = translateOptions(options, map);
146+
expect(result).toEqual({ alpha: 1, beta: 2, c: 3 });
147+
});
148+
149+
test('handles mapping to existing keys by overwriting', () => {
150+
const options = { a: 1, b: 2 };
151+
const map = { a: 'b' };
152+
const result = translateOptions(options, map);
153+
expect(result).toEqual({ b: 1 });
154+
});
155+
156+
test('handles undefined values', () => {
157+
const options = { a: undefined, b: null };
158+
const map = { a: 'newA', b: 'newB' };
159+
const result = translateOptions(options, map);
160+
expect(result).toEqual({ a: undefined, newB: null });
161+
});
162+
});
72163
});
73164

74165
describe('isNonInteractive', () => {

0 commit comments

Comments
 (0)