MISC: Make implicit string conversion consistent across all coding contracts (#2608)

This commit is contained in:
catloversg
2026-04-03 13:53:16 +07:00
committed by GitHub
parent d1b6acc57a
commit 8dcccdc5bb
13 changed files with 376 additions and 60 deletions

View File

@@ -0,0 +1,173 @@
import { CodingContractTypes, parseArrayString } from "../../../src/CodingContract/ContractTypes";
import { CodingContractName } from "../../../src/Enums";
import { getRecordEntries } from "../../../src/Types/Record";
beforeEach(() => {
jest.spyOn(console, "error").mockImplementation(jest.fn());
});
afterEach(() => {
jest.restoreAllMocks();
});
describe("Utility functions", () => {
test("parseArrayString", () => {
expect(parseArrayString("")).toStrictEqual([]);
expect(parseArrayString("[]")).toStrictEqual([]);
expect(parseArrayString(`""`)).toStrictEqual([""]);
expect(parseArrayString(`[""]`)).toStrictEqual([""]);
expect(parseArrayString(`"foo"`)).toStrictEqual(["foo"]);
expect(parseArrayString(`["foo"]`)).toStrictEqual(["foo"]);
expect(parseArrayString("0")).toStrictEqual([0]);
expect(parseArrayString("0,1")).toStrictEqual([0, 1]);
expect(parseArrayString("[0,1]")).toStrictEqual([0, 1]);
expect(parseArrayString(`[[]]`, true)).toStrictEqual([[]]);
expect(parseArrayString(`[[0]]`, true)).toStrictEqual([[0]]);
expect(parseArrayString(`[[0,1],[2,3]]`, true)).toStrictEqual([
[0, 1],
[2, 3],
]);
// Incorrectly wrapped as documented
expect(parseArrayString(`[ [0]]`, true)).toStrictEqual([[[0]]]);
// Preprocessing redundant whitespace
expect(parseArrayString(`[ [0]]`.replace(/\s/g, ""), true)).toStrictEqual([[0]]);
// Return as-is as documented
expect(parseArrayString(`[[1,2],3]`, true)).toStrictEqual([[1, 2], 3]);
expect(parseArrayString("[")).toStrictEqual(null);
expect(parseArrayString("]")).toStrictEqual(null);
expect(parseArrayString("foo")).toStrictEqual(null);
});
});
describe("Array", () => {
for (const [name, cct] of getRecordEntries(CodingContractTypes)) {
if (
![
CodingContractName.FindAllValidMathExpressions,
CodingContractName.GenerateIPAddresses,
CodingContractName.MergeOverlappingIntervals,
CodingContractName.Proper2ColoringOfAGraph,
CodingContractName.SanitizeParenthesesInExpression,
CodingContractName.SpiralizeMatrix,
CodingContractName.LargestRectangleInAMatrix,
].includes(name)
) {
continue;
}
test(name, () => {
expect(cct.convertAnswer("[")).toStrictEqual(null);
expect(cct.convertAnswer("]")).toStrictEqual(null);
});
}
});
describe("String array", () => {
for (const [name, cct] of getRecordEntries(CodingContractTypes)) {
if (
![
CodingContractName.FindAllValidMathExpressions,
CodingContractName.GenerateIPAddresses,
CodingContractName.SanitizeParenthesesInExpression,
].includes(name)
) {
continue;
}
test(name, () => {
expect(cct.convertAnswer("")).toStrictEqual([]);
expect(cct.convertAnswer("[]")).toStrictEqual([]);
expect(cct.convertAnswer(`""`)).toStrictEqual([""]);
expect(cct.convertAnswer(`[""]`)).toStrictEqual([""]);
expect(cct.convertAnswer(`"",""`)).toStrictEqual(["", ""]);
expect(cct.convertAnswer(`["",""]`)).toStrictEqual(["", ""]);
expect(cct.convertAnswer(`"foo"`)).toStrictEqual(["foo"]);
expect(cct.convertAnswer(`"foo","bar"`)).toStrictEqual(["foo", "bar"]);
expect(cct.convertAnswer(` "foo", "bar" `)).toStrictEqual(["foo", "bar"]);
expect(cct.convertAnswer(`"foo`)).toStrictEqual(null);
expect(cct.convertAnswer(`foo"`)).toStrictEqual(null);
expect(cct.convertAnswer(`'foo'`)).toStrictEqual(null);
expect(cct.convertAnswer(`\`foo\``)).toStrictEqual(null);
});
}
});
describe("Number array", () => {
for (const [name, cct] of getRecordEntries(CodingContractTypes)) {
if (![CodingContractName.Proper2ColoringOfAGraph, CodingContractName.SpiralizeMatrix].includes(name)) {
continue;
}
test(name, () => {
expect(cct.convertAnswer("")).toStrictEqual([]);
expect(cct.convertAnswer("[]")).toStrictEqual([]);
expect(cct.convertAnswer("0")).toStrictEqual([0]);
expect(cct.convertAnswer("[0]")).toStrictEqual([0]);
expect(cct.convertAnswer("0,1")).toStrictEqual([0, 1]);
expect(cct.convertAnswer("[0,1]")).toStrictEqual([0, 1]);
expect(cct.convertAnswer("[ 0, 1]")).toStrictEqual([0, 1]);
// Common issues with parseInt in old implementations of convertAnswer
expect(cct.convertAnswer("123abc")).toStrictEqual(null);
expect(cct.convertAnswer(`"0"`)).toStrictEqual(null);
expect(cct.convertAnswer("null")).toStrictEqual(null);
expect(cct.convertAnswer("undefined")).toStrictEqual(null);
if (name !== CodingContractName.Proper2ColoringOfAGraph) {
expect(cct.convertAnswer("12.34")).toStrictEqual([12.34]);
expect(cct.convertAnswer("1e3")).toStrictEqual([1000]);
}
});
}
});
describe("Array of arrays", () => {
test(CodingContractName.MergeOverlappingIntervals, () => {
const cct = CodingContractTypes[CodingContractName.MergeOverlappingIntervals];
// "" => []. With the current generate() and getAnswer(), both data and answer cannot be empty arrays, but in
// theory, if the input is an empty array, the output is also an empty array. The fact that the input cannot be an
// empty array is only an implementation detail of the internal functions, so an empty array is still a potentially
// correct answer.
expect(cct.convertAnswer("")).toStrictEqual([]);
// "[]" => []
expect(cct.convertAnswer("[]")).toStrictEqual([]);
expect(cct.convertAnswer("[0,0]")).toStrictEqual([[0, 0]]);
expect(cct.convertAnswer("[0, 0]")).toStrictEqual([[0, 0]]);
expect(cct.convertAnswer("[[0, 0]]")).toStrictEqual([[0, 0]]);
expect(cct.convertAnswer("[ [0, 0]]")).toStrictEqual([[0, 0]]);
expect(cct.convertAnswer("[1, 2], [3, 4]")).toStrictEqual([
[1, 2],
[3, 4],
]);
expect(cct.convertAnswer("[[1, 2], [3, 4]]")).toStrictEqual([
[1, 2],
[3, 4],
]);
expect(cct.convertAnswer("[[]]")).toStrictEqual(null);
});
test(CodingContractName.LargestRectangleInAMatrix, () => {
const cct = CodingContractTypes[CodingContractName.LargestRectangleInAMatrix];
expect(cct.convertAnswer("[0,0],[0,1]")).toStrictEqual([
[0, 0],
[0, 1],
]);
expect(cct.convertAnswer("[[0,0],[0,1]]")).toStrictEqual([
[0, 0],
[0, 1],
]);
expect(cct.convertAnswer("[ [0,0], [0,1]]")).toStrictEqual([
[0, 0],
[0, 1],
]);
// "" => [], and an empty array is invalid.
expect(cct.convertAnswer("")).toStrictEqual(null);
// "[]" => [], and an empty array is invalid.
expect(cct.convertAnswer("[]")).toStrictEqual(null);
expect(cct.convertAnswer("[0,0]")).toStrictEqual(null);
expect(cct.convertAnswer("[[]]")).toStrictEqual(null);
});
});