Skip to content

Commit 920dd80

Browse files
authored
Merge pull request #97 from nicolelim02/feat/collab
Display test cases
2 parents 69e7846 + ca07d5e commit 920dd80

File tree

7 files changed

+76
-85
lines changed

7 files changed

+76
-85
lines changed

backend/code-execution-service/src/controllers/codeExecutionControllers.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,17 @@ export const executeCode = async (req: Request, res: Response) => {
4141
try {
4242
// Get question test case files
4343
const qnsResponse = await questionService.get(`/${questionId}`);
44-
const { testcaseInputFileUrl, testcaseOutputFileUrl } =
44+
const { inputs: stdinList, outputs: expectedResultList } =
4545
qnsResponse.data.question;
4646

4747
// Extract test cases from input and output files
48-
const testCases = await testCasesApi(
49-
testcaseInputFileUrl,
50-
testcaseOutputFileUrl
51-
);
48+
// const testCases = await testCasesApi(
49+
// testcaseInputFileUrl,
50+
// testcaseOutputFileUrl
51+
// );
5252

53-
const stdinList: string[] = testCases.input;
54-
const expectedResultList: string[] = testCases.output;
53+
// const stdinList: string[] = testCases.input;
54+
// const expectedResultList: string[] = testCases.output;
5555

5656
if (stdinList.length !== expectedResultList.length) {
5757
res.status(400).json({

backend/code-execution-service/tests/codeExecutionRoutes.spec.ts

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,12 @@ describe("Code execution routes", () => {
5757
(questionService.get as jest.Mock).mockResolvedValue({
5858
data: {
5959
question: {
60-
testcaseInputFileUrl: "https://peerprep.com/input",
61-
testcaseOutputFileUrl: "https://peerprep.com/output",
60+
inputs: ["1", "2"],
61+
outputs: ["1"],
6262
},
6363
},
6464
});
6565

66-
(testCasesApi as jest.Mock).mockResolvedValue({
67-
input: ["1", "2"],
68-
output: ["1"],
69-
});
70-
7166
const response = await request.post(`${BASE_URL}/run`).send({
7267
language: "python",
7368
code: "print('Hello, world!')",
@@ -81,23 +76,20 @@ describe("Code execution routes", () => {
8176
(questionService.get as jest.Mock).mockResolvedValue({
8277
data: {
8378
question: {
84-
testcaseInputFileUrl: "https://peerprep.com/input",
85-
testcaseOutputFileUrl: "https://peerprep.com/output",
79+
inputs: ["1", "2"],
80+
outputs: ["1", "2"],
8681
},
8782
},
8883
});
8984

90-
(testCasesApi as jest.Mock).mockResolvedValue({
91-
input: ["1", "2"],
92-
output: ["1", "4"],
93-
});
94-
9585
const response = await request.post(`${BASE_URL}/run`).send({
9686
language: "python",
9787
code: "print(input())",
9888
questionId: "1234",
9989
});
10090

91+
console.log(response.body);
92+
10193
expect(response.status).toBe(200);
10294
expect(response.body.message).toBe(SUCCESS_MESSAGE);
10395
expect(response.body.data).toBeInstanceOf(Array);

backend/question-service/src/controllers/questionController.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { Request, Response } from "express";
22
import Question, { IQuestion } from "../models/Question.ts";
3-
import { checkIsExistingQuestion, sortAlphabetically } from "../utils/utils.ts";
3+
import {
4+
checkIsExistingQuestion,
5+
getFileContent,
6+
sortAlphabetically,
7+
} from "../utils/utils.ts";
48
import {
59
DUPLICATE_QUESTION_MESSAGE,
610
QN_DESC_EXCEED_CHAR_LIMIT_MESSAGE,
@@ -76,7 +80,7 @@ export const createQuestion = async (
7680

7781
res.status(201).json({
7882
message: QN_CREATED_MESSAGE,
79-
question: formatQuestionIndivResponse(newQuestion),
83+
question: await formatQuestionIndivResponse(newQuestion),
8084
});
8185
} catch (error) {
8286
console.log(error);
@@ -221,7 +225,7 @@ export const updateQuestion = async (
221225

222226
res.status(200).json({
223227
message: "Question updated successfully",
224-
question: formatQuestionIndivResponse(updatedQuestion as IQuestion),
228+
question: await formatQuestionIndivResponse(updatedQuestion as IQuestion),
225229
});
226230
} catch (error) {
227231
res.status(500).json({ message: SERVER_ERROR_MESSAGE, error });
@@ -322,7 +326,7 @@ export const readQuestionIndiv = async (
322326

323327
res.status(200).json({
324328
message: QN_RETRIEVED_MESSAGE,
325-
question: formatQuestionIndivResponse(questionDetails),
329+
question: await formatQuestionIndivResponse(questionDetails),
326330
});
327331
} catch (error) {
328332
res.status(500).json({ message: SERVER_ERROR_MESSAGE, error });
@@ -353,7 +357,7 @@ export const readRandomQuestion = async (
353357

354358
res.status(200).json({
355359
message: QN_RETRIEVED_MESSAGE,
356-
question: formatQuestionIndivResponse(chosenQuestion),
360+
question: await formatQuestionIndivResponse(chosenQuestion),
357361
});
358362
} catch (error) {
359363
res.status(500).json({ message: SERVER_ERROR_MESSAGE, error });
@@ -393,15 +397,22 @@ const formatQuestionResponse = (question: IQuestion) => {
393397
};
394398
};
395399

396-
const formatQuestionIndivResponse = (question: IQuestion) => {
400+
const formatQuestionIndivResponse = async (question: IQuestion) => {
401+
const testcaseDelimiter = "\n\n";
402+
const inputs = (await getFileContent(question.testcaseInputFileUrl))
403+
.replace(/\r\n/g, "\n")
404+
.split(testcaseDelimiter);
405+
const outputs = (await getFileContent(question.testcaseOutputFileUrl))
406+
.replace(/\r\n/g, "\n")
407+
.split(testcaseDelimiter);
397408
return {
398409
id: question._id,
399410
title: question.title,
400411
description: question.description,
401412
complexity: question.complexity,
402413
categories: question.category,
403-
testcaseInputFileUrl: question.testcaseInputFileUrl,
404-
testcaseOutputFileUrl: question.testcaseOutputFileUrl,
414+
inputs,
415+
outputs,
405416
pythonTemplate: question.pythonTemplate,
406417
javaTemplate: question.javaTemplate,
407418
cTemplate: question.cTemplate,

backend/question-service/src/utils/utils.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
import axios from "axios";
12
import mongoose from "mongoose";
23
import { v4 as uuidv4 } from "uuid";
34

45
import { bucket } from "../config/firebase";
5-
66
import Question from "../models/Question";
77

88
export const checkIsExistingQuestion = async (
@@ -50,6 +50,16 @@ export const uploadFileToFirebase = async (
5050
});
5151
};
5252

53+
export const getFileContent = async (url: string): Promise<string> => {
54+
try {
55+
const { data } = await axios.get(url);
56+
return data;
57+
} catch (error) {
58+
console.error(error);
59+
return "";
60+
}
61+
};
62+
5363
export const sortAlphabetically = (arr: string[]) => {
5464
return [...arr].sort((a, b) =>
5565
a.localeCompare(b, undefined, { sensitivity: "base" }),

frontend/src/components/TestCase/index.tsx

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { Box, styled, Typography } from "@mui/material";
22

33
type TestCaseProps = {
44
input: string;
5-
output: string;
5+
output?: string;
66
stdout: string;
7-
result: string;
7+
result?: string;
88
};
99

1010
const StyledBox = styled(Box)(({ theme }) => ({
@@ -30,16 +30,20 @@ const TestCase: React.FC<TestCaseProps> = ({
3030
<Typography variant="overline">Input</Typography>
3131
<StyledTypography fontFamily={"monospace"}>{input}</StyledTypography>
3232
</StyledBox>
33+
{output && (
34+
<StyledBox>
35+
<Typography variant="overline">Output</Typography>
36+
<StyledTypography fontFamily={"monospace"}>{output}</StyledTypography>
37+
</StyledBox>
38+
)}
39+
{stdout && (
40+
<StyledBox>
41+
<Typography variant="overline">Stdout</Typography>
42+
<StyledTypography fontFamily={"monospace"}>{stdout}</StyledTypography>
43+
</StyledBox>
44+
)}
3345
<StyledBox>
34-
<Typography variant="overline">Output</Typography>
35-
<StyledTypography fontFamily={"monospace"}>{output}</StyledTypography>
36-
</StyledBox>
37-
<StyledBox>
38-
<Typography variant="overline">Standard output</Typography>
39-
<StyledTypography fontFamily={"monospace"}>{stdout}</StyledTypography>
40-
</StyledBox>
41-
<StyledBox>
42-
<Typography variant="overline">Result</Typography>
46+
<Typography variant="overline">Expected</Typography>
4347
<StyledTypography fontFamily={"monospace"}>{result}</StyledTypography>
4448
</StyledBox>
4549
</Box>

frontend/src/pages/CollabSandbox/index.tsx

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -34,30 +34,6 @@ import CodeEditor from "../../components/CodeEditor";
3434
import { CollabSessionData, join, leave } from "../../utils/collabSocket";
3535
import { toast } from "react-toastify";
3636

37-
// hardcode for now...
38-
39-
type TestCase = {
40-
input: string;
41-
output: string;
42-
stdout: string;
43-
result: string;
44-
};
45-
46-
const testcases: TestCase[] = [
47-
{
48-
input: "1 2 3 4",
49-
output: "1 2 3 4",
50-
stdout: "1\n2\n3\n4",
51-
result: "1 2 3 4",
52-
},
53-
{
54-
input: "5 6 7 8",
55-
output: "5 6 7 8",
56-
stdout: "5\n6\n7\n8",
57-
result: "5 6 7 8",
58-
},
59-
];
60-
6137
const CollabSandbox: React.FC = () => {
6238
const [editorState, setEditorState] = useState<CollabSessionData | null>(
6339
null
@@ -267,7 +243,7 @@ const CollabSandbox: React.FC = () => {
267243

268244
<TabPanel value={selectedTab} selected="tests">
269245
<Box sx={(theme) => ({ margin: theme.spacing(2, 0) })}>
270-
{[...Array(testcases.length)]
246+
{[...Array(selectedQuestion.inputs.length)]
271247
.map((_, index) => index + 1)
272248
.map((i) => (
273249
<Button
@@ -283,11 +259,12 @@ const CollabSandbox: React.FC = () => {
283259
</Button>
284260
))}
285261
</Box>
262+
{/* display result of each test case in the output (result) and stdout (any print statements executed) */}
286263
<TestCase
287-
input={testcases[selectedTestcase].input}
288-
output={testcases[selectedTestcase].output}
289-
stdout={testcases[selectedTestcase].stdout}
290-
result={testcases[selectedTestcase].result}
264+
input={selectedQuestion.inputs[selectedTestcase]}
265+
output={""}
266+
stdout={""}
267+
result={selectedQuestion.outputs[selectedTestcase]}
291268
/>
292269
</TabPanel>
293270
<TabPanel value={selectedTab} selected="chat">

frontend/src/reducers/questionReducer.ts

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,17 @@ type QuestionDetail = {
1818
description: string;
1919
complexity: string;
2020
categories: Array<string>;
21+
inputs: Array<string>;
22+
outputs: Array<string>;
2123
pythonTemplate: string;
2224
javaTemplate: string;
2325
cTemplate: string;
2426
};
2527

26-
type QuestionDetailWithUrl = QuestionDetail & {
27-
testcaseInputFileUrl: string;
28-
testcaseOutputFileUrl: string;
29-
};
28+
// type QuestionDetailWithUrl = QuestionDetail & {
29+
// testcaseInputFileUrl: string;
30+
// testcaseOutputFileUrl: string;
31+
// };
3032

3133
type QuestionListDetail = {
3234
id: string;
@@ -56,26 +58,21 @@ enum QuestionActionTypes {
5658

5759
type QuestionActions = {
5860
type: QuestionActionTypes;
59-
payload:
60-
| QuestionList
61-
| QuestionDetail
62-
| QuestionDetailWithUrl
63-
| string[]
64-
| string;
61+
payload: QuestionList | QuestionDetail | string[] | string;
6562
};
6663

6764
type QuestionsState = {
6865
questionCategories: Array<string>;
6966
questions: Array<QuestionListDetail>;
7067
questionCount: number;
71-
selectedQuestion: QuestionDetailWithUrl | null;
68+
selectedQuestion: QuestionDetail | null;
7269
questionCategoriesError: string | null;
7370
questionListError: string | null;
7471
selectedQuestionError: string | null;
7572
};
7673

7774
// eslint-disable-next-line @typescript-eslint/no-explicit-any
78-
const isQuestion = (question: any): question is QuestionDetailWithUrl => {
75+
const isQuestion = (question: any): question is QuestionDetail => {
7976
if (!question || typeof question !== "object") {
8077
return false;
8178
}
@@ -272,7 +269,7 @@ export const getQuestionById = (
272269

273270
export const updateQuestionById = async (
274271
questionId: string,
275-
question: Omit<QuestionDetailWithUrl, "id">,
272+
question: Omit<QuestionDetail, "id">,
276273
testcaseFiles: TestcaseFiles,
277274
dispatch: Dispatch<QuestionActions>
278275
): Promise<boolean> => {
@@ -309,8 +306,8 @@ export const updateQuestionById = async (
309306
description: question.description,
310307
complexity: question.complexity,
311308
category: question.categories,
312-
testcaseInputFileUrl: question.testcaseInputFileUrl,
313-
testcaseOutputFileUrl: question.testcaseOutputFileUrl,
309+
// testcaseInputFileUrl: question.testcaseInputFileUrl,
310+
// testcaseOutputFileUrl: question.testcaseOutputFileUrl,
314311
...urls,
315312
pythonTemplate: question.pythonTemplate,
316313
javaTemplate: question.javaTemplate,

0 commit comments

Comments
 (0)