Skip to content

Commit f993258

Browse files
authored
CodeQL model editor: Make Type a selectable model kind for Ruby (#3224)
1 parent c5517e0 commit f993258

2 files changed

Lines changed: 94 additions & 10 deletions

File tree

extensions/ql-vscode/src/view/model-editor/ModelTypeDropdown.tsx

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ChangeEvent } from "react";
2-
import { useCallback } from "react";
2+
import { useCallback, useMemo } from "react";
33
import type {
44
ModeledMethod,
55
ModeledMethodType,
@@ -12,19 +12,11 @@ import type { Method } from "../../model-editor/method";
1212
import { createEmptyModeledMethod } from "../../model-editor/modeled-method-empty";
1313
import type { Mutable } from "../../common/mutable";
1414
import { ReadonlyDropdown } from "../common/ReadonlyDropdown";
15-
import type { QueryLanguage } from "../../common/query-language";
15+
import { QueryLanguage } from "../../common/query-language";
1616
import { getModelsAsDataLanguage } from "../../model-editor/languages";
1717
import type { ModelingStatus } from "../../model-editor/shared/modeling-status";
1818
import { InputDropdown } from "./InputDropdown";
1919

20-
const options: Array<{ value: ModeledMethodType; label: string }> = [
21-
{ value: "none", label: "Unmodeled" },
22-
{ value: "source", label: "Source" },
23-
{ value: "sink", label: "Sink" },
24-
{ value: "summary", label: "Flow summary" },
25-
{ value: "neutral", label: "Neutral" },
26-
];
27-
2820
type Props = {
2921
language: QueryLanguage;
3022
method: Method;
@@ -40,6 +32,21 @@ export const ModelTypeDropdown = ({
4032
modelingStatus,
4133
onChange,
4234
}: Props): JSX.Element => {
35+
const options = useMemo(() => {
36+
const baseOptions: Array<{ value: ModeledMethodType; label: string }> = [
37+
{ value: "none", label: "Unmodeled" },
38+
{ value: "source", label: "Source" },
39+
{ value: "sink", label: "Sink" },
40+
{ value: "summary", label: "Flow summary" },
41+
{ value: "neutral", label: "Neutral" },
42+
];
43+
if (language === QueryLanguage.Ruby) {
44+
baseOptions.push({ value: "type", label: "Type" });
45+
}
46+
47+
return baseOptions;
48+
}, [language]);
49+
4350
const handleChange = useCallback(
4451
(e: ChangeEvent<HTMLSelectElement>) => {
4552
const modelsAsDataLanguage = getModelsAsDataLanguage(language);
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { userEvent } from "@testing-library/user-event";
2+
import { render, screen } from "@testing-library/react";
3+
import { createNoneModeledMethod } from "../../../../test/factories/model-editor/modeled-method-factories";
4+
import { QueryLanguage } from "../../../common/query-language";
5+
import { ModelTypeDropdown } from "../ModelTypeDropdown";
6+
import { createMethod } from "../../../../test/factories/model-editor/method-factories";
7+
8+
describe(ModelTypeDropdown.name, () => {
9+
const onChange = jest.fn();
10+
11+
beforeEach(() => {
12+
onChange.mockReset();
13+
});
14+
15+
it("allows changing the type", async () => {
16+
const method = createMethod();
17+
const modeledMethod = createNoneModeledMethod();
18+
19+
render(
20+
<ModelTypeDropdown
21+
language={QueryLanguage.Java}
22+
modeledMethod={modeledMethod}
23+
modelingStatus="unsaved"
24+
onChange={onChange}
25+
method={method}
26+
/>,
27+
);
28+
29+
await userEvent.selectOptions(screen.getByRole("combobox"), "source");
30+
expect(onChange).toHaveBeenCalledWith(
31+
expect.objectContaining({
32+
type: "source",
33+
}),
34+
);
35+
});
36+
37+
it("allows changing the type to 'Type' for Ruby", async () => {
38+
const method = createMethod();
39+
const modeledMethod = createNoneModeledMethod();
40+
41+
render(
42+
<ModelTypeDropdown
43+
language={QueryLanguage.Ruby}
44+
modeledMethod={modeledMethod}
45+
modelingStatus="unsaved"
46+
onChange={onChange}
47+
method={method}
48+
/>,
49+
);
50+
51+
await userEvent.selectOptions(screen.getByRole("combobox"), "type");
52+
expect(onChange).toHaveBeenCalledWith(
53+
expect.objectContaining({
54+
type: "type",
55+
}),
56+
);
57+
});
58+
59+
it("does not allow changing the type to 'Type' for Java", async () => {
60+
const method = createMethod();
61+
const modeledMethod = createNoneModeledMethod();
62+
63+
render(
64+
<ModelTypeDropdown
65+
language={QueryLanguage.Java}
66+
modeledMethod={modeledMethod}
67+
modelingStatus="unsaved"
68+
onChange={onChange}
69+
method={method}
70+
/>,
71+
);
72+
73+
expect(
74+
screen.queryByRole("option", { name: "Type" }),
75+
).not.toBeInTheDocument();
76+
});
77+
});

0 commit comments

Comments
 (0)