Skip to content

Commit

Permalink
Merge branch 'sosy-lab:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
justfeelix authored Mar 22, 2024
2 parents 8a97073 + 64d73c4 commit e0aa357
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 43 deletions.
2 changes: 1 addition & 1 deletion benchexec/tablegenerator/react-table/build/main.min.js

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,11 @@ export default class Overview extends React.Component {
filters
.filter((filter) => filter.id !== "id")
.forEach((filter) => {
const [runsetIdx, , columnIdx] = filter.id.split("_");
const type = this.state.tools[runsetIdx]["columns"][columnIdx].type;
const filterSplitArray = filter.id.split("_");
const type =
this.state.tools[filterSplitArray[0]]["columns"][
filterSplitArray.at(-1)
].type;
filter.type = type;
});

Expand Down
149 changes: 125 additions & 24 deletions benchexec/tablegenerator/react-table/src/tests/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
makeFilterDeserializer,
splitUrlPathForMatchingPrefix,
makeRegExp,
tokenizePart,
} from "../utils/utils";

describe("isStatusOk", () => {
Expand Down Expand Up @@ -134,54 +135,71 @@ describe("hashRouting helpers", () => {
const baseUrl = "http://example.com";
const params = { key1: "value1", key2: "value2" };

expect(constructHashURL(baseUrl, params)).toEqual(
"http://example.com?key1=value1&key2=value2",
);
const expected = {
newUrl: "http://example.com?key1=value1&key2=value2",
queryString: "?key1=value1&key2=value2",
};
expect(constructHashURL(baseUrl, params)).toEqual(expected);
});

test("should construct URL hash with provided parameters and keep the exisiting parameters", () => {
const baseUrl = "http://example.com?existingKey=existingValue";
const params = { key1: "value1", key2: "value2" };

expect(constructHashURL(baseUrl, params)).toEqual(
"http://example.com?existingKey=existingValue&key1=value1&key2=value2",
);
const expected = {
newUrl:
"http://example.com?existingKey=existingValue&key1=value1&key2=value2",
queryString: "?existingKey=existingValue&key1=value1&key2=value2",
};
expect(constructHashURL(baseUrl, params)).toEqual(expected);
});

test("should return the same URL with exisiting params if no parameters are provided", () => {
const baseUrl = "http://example.com?exisitingKey=existingValue";
const params = {};

expect(constructHashURL(baseUrl, params)).toEqual(
"http://example.com?exisitingKey=existingValue",
);
const expected = {
newUrl: "http://example.com?exisitingKey=existingValue",
queryString: "?exisitingKey=existingValue",
};

expect(constructHashURL(baseUrl, params)).toEqual(expected);
});

test("should override existing parameters with new ones", () => {
const baseUrl = "http://example.com?key1=value1&key2=value2";
const params = { key2: "newValue" };

expect(constructHashURL(baseUrl, params)).toEqual(
"http://example.com?key1=value1&key2=newValue",
);
const expected = {
newUrl: "http://example.com?key1=value1&key2=newValue",
queryString: "?key1=value1&key2=newValue",
};

expect(constructHashURL(baseUrl, params)).toEqual(expected);
});

test("should remove exisiting parameters if they are updated to undefined", () => {
const baseUrl = "http://example.com?key1=value1&key2=value2";
const params = { key2: undefined };

expect(constructHashURL(baseUrl, params)).toEqual(
"http://example.com?key1=value1",
);
const expected = {
newUrl: "http://example.com?key1=value1",
queryString: "?key1=value1",
};

expect(constructHashURL(baseUrl, params)).toEqual(expected);
});

test("should remove exisiting parameters if they are updated to null", () => {
const baseUrl = "http://example.com?key1=value1&key2=value2";
const params = { key2: null };

expect(constructHashURL(baseUrl, params)).toEqual(
"http://example.com?key1=value1",
);
const expected = {
newUrl: "http://example.com?key1=value1",
queryString: "?key1=value1",
};

expect(constructHashURL(baseUrl, params)).toEqual(expected);
});

test("should not remove exisiting parameters if they are updated to falsy values", () => {
Expand All @@ -192,9 +210,12 @@ describe("hashRouting helpers", () => {
key3: 0,
};

expect(constructHashURL(baseUrl, params)).toEqual(
"http://example.com?key1=&key2=false&key3=0",
);
const expected = {
newUrl: "http://example.com?key1=&key2=false&key3=0",
queryString: "?key1=&key2=false&key3=0",
};

expect(constructHashURL(baseUrl, params)).toEqual(expected);
});
});
});
Expand Down Expand Up @@ -239,9 +260,29 @@ describe("decodeFilter", () => {
expect(decodeFilter(filter)).toEqual(expected);
});

test("should throw errors if there are more than two '_' in the filter id", () => {
expect(() => decodeFilter("0__cputime_")).toThrow();
expect(() => decodeFilter("0_cputime_1_2")).toThrow();
test("should throw errors if there are is only one '_' in the filter id", () => {
expect(() => decodeFilter("0cputime_")).toThrow();
expect(() => decodeFilter("0_cputime2")).toThrow();
});

test("should decode correctly with more than two '_' in the filter id", () => {
const filter = "0_cpu_time_1";
const expected = { tool: "0", name: "cpu_time", column: "1" };
expect(decodeFilter(filter)).toEqual(expected);
});
});

describe("tokenizePart", () => {
test("should tokenizePart to get Filter keys", () => {
const string = "id_any(value(%29)),0(1*cputime*(value(2)))";
const expected = { 0: "1*cputime*(value(2))", id_any: "value(%29)" };
expect(tokenizePart(string)).toEqual(expected);
});

test("should tokenizePart to get Filter values", () => {
const string = "value(%29)";
const expected = { value: ")" };
expect(tokenizePart(string, true)).toEqual(expected);
});
});

Expand Down Expand Up @@ -278,6 +319,34 @@ describe("serialization", () => {
expect(serializer(filter)).toBe(expected);
});

test("should serialize id filters with parentheses", () => {
const filter = [{ id: "id", values: ["(", ")"] }];
const expected = "id(values(%28,%29))";

expect(serializer(filter)).toBe(expected);
});

test("should serialize id filter to escape special characters", () => {
const filter = [{ id: "id", value: "?#&=(),*", isTableTabFilter: true }];
const expected = "id_any(value(%3F%23%26%3D%28%29%2C*))";

expect(serializer(filter)).toBe(expected);
});

test("should serialize id filter with one opening parentheses", () => {
const filter = [{ id: "id", value: "(", isTableTabFilter: true }];
const expected = "id_any(value(%28))";

expect(serializer(filter)).toBe(expected);
});

test("should serialize id filter with one closing parentheses", () => {
const filter = [{ id: "id", value: ")", isTableTabFilter: true }];
const expected = "id_any(value(%29))";

expect(serializer(filter)).toBe(expected);
});

test("should serialize normal value filters for one runset", () => {
const filter = [
{ id: "0_cputime_1", value: "1223:4567" },
Expand Down Expand Up @@ -598,6 +667,38 @@ describe("Filter deserialization", () => {
expect(deserializer(string)).toStrictEqual(expected);
});

test("should serialize id filters with parentheses", () => {
const string = "id(values(%28,%29))";

const expected = [{ id: "id", values: ["(", ")"] }];

expect(deserializer(string)).toStrictEqual(expected);
});

test("should deserialize id filter with one opening parentheses", () => {
const string = "id_any(value(%28))";

const expected = [{ id: "id", value: "(", isTableTabFilter: true }];

expect(deserializer(string)).toStrictEqual(expected);
});

test("should deserialize id filter with one closing parentheses", () => {
const string = "id_any(value(%29))";

const expected = [{ id: "id", value: ")", isTableTabFilter: true }];

expect(deserializer(string)).toStrictEqual(expected);
});

test("should deserialize Table Tab Id filter with special characters", () => {
const string = "id_any(value(%3F%23%26%3D()%2C*))*";

const expected = [{ id: "id", value: "?#&=(),*", isTableTabFilter: true }];

expect(deserializer(string)).toStrictEqual(expected);
});

test("should deserialize normal values for one runset", () => {
const string = "0(1*cputime*(value(%3A1234)))";

Expand Down
64 changes: 48 additions & 16 deletions benchexec/tablegenerator/react-table/src/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,14 +203,14 @@ const EXTENDED_DISCRETE_COLOR_RANGE = [
];

/**
* Parses the search parameters from the URL hash or a provided string.
* Parses and decodes the search parameters except filter from the URL hash or a provided string.
*
* @param {string} - Optional string to parse. If not provided, parses the URL hash of the current document.
* @returns {Object} - An object containing the parsed search parameters.
*/
const getURLParameters = (str) => {
// Split the URL string into parts using "?" as a delimiter
const urlParts = (str || decodeURI(document.location.href)).split("?");
const urlParts = (str || document.location.href).split("?");

// Extract the search part of the URL
const search = urlParts.length > 1 ? urlParts.slice(1).join("?") : undefined;
Expand All @@ -223,8 +223,11 @@ const getURLParameters = (str) => {
// Split the search string into key-value pairs and generate an object from them
const keyValuePairs = search.split("&").map((pair) => pair.split("="));
const out = {};

// All parameters in the search string are decoded except filter to allow filter handling later on its own
for (const [key, ...value] of keyValuePairs) {
out[key] = value.join("=");
out[decodeURI(key)] =
key === "filter" ? value.join("=") : decodeURI(value.join("="));
}

return out;
Expand Down Expand Up @@ -257,7 +260,10 @@ export const constructHashURL = (url, params = {}) => {
const queryString = constructQueryString(mergedParams);
const baseURL = url.split("?")[0];

return queryString.length > 0 ? `${baseURL}?${queryString}` : baseURL;
return {
newUrl: queryString.length > 0 ? `${baseURL}?${queryString}` : baseURL,
queryString: `?${queryString}`,
};
};

/**
Expand All @@ -269,10 +275,13 @@ export const constructHashURL = (url, params = {}) => {
* @returns {void}
*/
const setURLParameter = (params = {}, history = null) => {
const newUrl = constructHashURL(document.location.href, params);

const { newUrl, queryString } = constructHashURL(
document.location.href,
params,
);
if (history && history.push) {
history.push(newUrl);
history.push(queryString);
return;
}
document.location.href = newUrl;
};
Expand Down Expand Up @@ -363,6 +372,13 @@ function makeStatusColumnFilter(
return statusColumnFilter.join(",");
}

function escapeParentheses(value) {
if (typeof value !== "string") {
throw new Error("Invalid value type");
}
return value.replaceAll("(", "%28").replaceAll(")", "%29");
}

export const makeRegExp = (value) => {
if (typeof value !== "string") {
throw new Error("Invalid value type for converting to RegExp");
Expand All @@ -384,13 +400,18 @@ export const decodeFilter = (filterID) => {
}
const splitedArray = filterID.split("_");

if (splitedArray.length > 3) {
if (splitedArray.length === 2) {
throw new Error("Invalid filter ID");
}

// tool is always the first element value of the splitedArray
// column is always the last element value of the splitedArray
// name is the concatenation of remaining elements in between first and last element of splitedArray, separated by _
return {
tool: splitedArray[0],
name: splitedArray[1],
column: splitedArray[2],
name:
splitedArray.length > 2 ? splitedArray.slice(1, -1).join("_") : undefined,
column: splitedArray.length > 2 ? splitedArray.at(-1) : undefined,
};
};

Expand Down Expand Up @@ -453,11 +474,19 @@ const makeFilterSerializer =
const { ids, ...rest } = groupedFilters;
const runsetFilters = [];
if (ids) {
runsetFilters.push(`id(values(${ids.values.map(escape).join(",")}))`);
runsetFilters.push(
`id(values(${ids.values
.map((val) => escapeParentheses(encodeURIComponent(val)))
.join(",")}))`,
);
}
if (tableTabIdFilters) {
tableTabIdFilters.forEach((filter) => {
runsetFilters.push(`id_any(value(${filter.value}))`);
runsetFilters.push(
`id_any(value(${escapeParentheses(
encodeURIComponent(filter.value),
)}))`,
);
});
}
for (const [tool, column] of Object.entries(rest)) {
Expand Down Expand Up @@ -490,7 +519,7 @@ const makeFilterSerializer =
return filterString;
};

const tokenizePart = (string) => {
export const tokenizePart = (string, decodeValue = false) => {
const out = {};
let openBrackets = 0;

Expand All @@ -513,7 +542,7 @@ const tokenizePart = (string) => {
firstBracket + 1,
buf.length - 1 - (firstBracket + 1),
);
out[key] = value;
out[key] = decodeValue ? decodeURIComponent(value) : value;
}
continue;
}
Expand Down Expand Up @@ -609,7 +638,8 @@ const makeFilterDeserializer =
} else if (token === "id_any") {
out.push({
id: "id",
...tokenizePart(filter),
...tokenizePart(filter, true),
isTableTabFilter: true,
});
continue;
}
Expand All @@ -619,7 +649,9 @@ const makeFilterDeserializer =
const parsedColumnFilters = {};
for (const [key, columnFilter] of Object.entries(columnFilters)) {
const [columnId, columnTitle] = key.split("*");
const name = `${runsetId}_${unescape(columnTitle)}_${columnId}`;
const name = `${runsetId}_${decodeURIComponent(
columnTitle,
)}_${columnId}`;
const parsedFilters = parsedColumnFilters[name] || [];
const tokenizedFilter = tokenizePart(columnFilter);

Expand Down

0 comments on commit e0aa357

Please sign in to comment.