From bb3d7d223dcace0a132f6abf6b5d8f48e541878a Mon Sep 17 00:00:00 2001 From: LeonWehrhahn Date: Thu, 9 Jan 2025 15:49:21 +0100 Subject: [PATCH 1/5] Refactor feedback utility functions to separate manual and automatic unreferenced feedback filtering --- .../participate/modeling-submission.component.ts | 4 ++-- .../app/exercises/shared/result/result.utils.ts | 15 ++++++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/webapp/app/exercises/modeling/participate/modeling-submission.component.ts b/src/main/webapp/app/exercises/modeling/participate/modeling-submission.component.ts index b77b05f098dd..3c0e259e7707 100644 --- a/src/main/webapp/app/exercises/modeling/participate/modeling-submission.component.ts +++ b/src/main/webapp/app/exercises/modeling/participate/modeling-submission.component.ts @@ -15,7 +15,7 @@ import { ModelingAssessmentService } from 'app/exercises/modeling/assess/modelin import { ModelingSubmissionService } from 'app/exercises/modeling/participate/modeling-submission.service'; import { ModelingEditorComponent } from 'app/exercises/modeling/shared/modeling-editor.component'; import { getExerciseDueDate, hasExerciseDueDatePassed } from 'app/exercises/shared/exercise/exercise.utils'; -import { addParticipationToResult, getUnreferencedFeedback } from 'app/exercises/shared/result/result.utils'; +import { addParticipationToResult, getAutomaticUnreferencedFeedback } from 'app/exercises/shared/result/result.utils'; import { AccountService } from 'app/core/auth/account.service'; import { GuidedTourService } from 'app/guided-tour/guided-tour.service'; import { modelingTour } from 'app/guided-tour/tours/modeling-tour'; @@ -664,7 +664,7 @@ export class ModelingSubmissionComponent implements OnInit, OnDestroy, Component get unreferencedFeedback(): Feedback[] | undefined { if (this.assessmentResult?.feedbacks) { checkSubsequentFeedbackInAssessment(this.assessmentResult.feedbacks); - return getUnreferencedFeedback(this.assessmentResult.feedbacks); + return getAutomaticUnreferencedFeedback(this.assessmentResult.feedbacks); } return undefined; } diff --git a/src/main/webapp/app/exercises/shared/result/result.utils.ts b/src/main/webapp/app/exercises/shared/result/result.utils.ts index c77cc3a9fcf2..8e2b2eb99767 100644 --- a/src/main/webapp/app/exercises/shared/result/result.utils.ts +++ b/src/main/webapp/app/exercises/shared/result/result.utils.ts @@ -121,11 +121,16 @@ export const addParticipationToResult = (result: Result | undefined, participati * @returns an array with the unreferenced feedback of the result */ export const getUnreferencedFeedback = (feedbacks: Feedback[] | undefined): Feedback[] | undefined => { - return feedbacks - ? feedbacks.filter( - (feedbackElement) => !feedbackElement.reference && (feedbackElement.type === FeedbackType.MANUAL_UNREFERENCED || feedbackElement.type === FeedbackType.AUTOMATIC), - ) - : undefined; + return feedbacks ? feedbacks.filter((feedbackElement) => !feedbackElement.reference && feedbackElement.type === FeedbackType.MANUAL_UNREFERENCED) : undefined; +}; + +/** + * searches for all unreferenced feedback of type AUTOMATIC in an array of feedbacks of a result + * @param feedbacks the feedback of a result + * @returns an array with the unreferenced feedback of the result + */ +export const getAutomaticUnreferencedFeedback = (feedbacks: Feedback[] | undefined): Feedback[] | undefined => { + return feedbacks ? feedbacks.filter((feedbackElement) => !feedbackElement.reference && feedbackElement.type === FeedbackType.AUTOMATIC) : undefined; }; export function isAIResultAndFailed(result: Result | undefined): boolean { From 7b54b4b110f7245dbb81fa64ed42fa10b821d062 Mon Sep 17 00:00:00 2001 From: LeonWehrhahn Date: Thu, 9 Jan 2025 18:06:54 +0100 Subject: [PATCH 2/5] Rename feedback utility function --- .../participate/file-upload-submission.component.ts | 4 ++-- .../participate/code-editor-student-container.component.ts | 4 ++-- src/main/webapp/app/exercises/shared/result/result.utils.ts | 6 +++--- .../app/exercises/text/participate/text-editor.component.ts | 4 ++-- .../javascript/spec/component/utils/result.utils.spec.ts | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/webapp/app/exercises/file-upload/participate/file-upload-submission.component.ts b/src/main/webapp/app/exercises/file-upload/participate/file-upload-submission.component.ts index ebd49234be13..2157ebc343b1 100644 --- a/src/main/webapp/app/exercises/file-upload/participate/file-upload-submission.component.ts +++ b/src/main/webapp/app/exercises/file-upload/participate/file-upload-submission.component.ts @@ -22,7 +22,7 @@ import { ButtonType } from 'app/shared/components/button.component'; import { Result } from 'app/entities/result.model'; import { AccountService } from 'app/core/auth/account.service'; import { getFirstResultWithComplaint, getLatestSubmissionResult } from 'app/entities/submission.model'; -import { addParticipationToResult, getUnreferencedFeedback } from 'app/exercises/shared/result/result.utils'; +import { addParticipationToResult, getManualUnreferencedFeedback } from 'app/exercises/shared/result/result.utils'; import { Feedback, checkSubsequentFeedbackInAssessment } from 'app/entities/feedback.model'; import { onError } from 'app/shared/util/global.utils'; import { getCourseFromExercise } from 'app/entities/exercise.model'; @@ -247,7 +247,7 @@ export class FileUploadSubmissionComponent implements OnInit, ComponentCanDeacti get unreferencedFeedback(): Feedback[] | undefined { if (this.result?.feedbacks) { checkSubsequentFeedbackInAssessment(this.result.feedbacks); - return getUnreferencedFeedback(this.result.feedbacks); + return getManualUnreferencedFeedback(this.result.feedbacks); } return undefined; } diff --git a/src/main/webapp/app/exercises/programming/participate/code-editor-student-container.component.ts b/src/main/webapp/app/exercises/programming/participate/code-editor-student-container.component.ts index 697507764dac..bb9a508331d6 100644 --- a/src/main/webapp/app/exercises/programming/participate/code-editor-student-container.component.ts +++ b/src/main/webapp/app/exercises/programming/participate/code-editor-student-container.component.ts @@ -14,7 +14,7 @@ import { DomainType } from 'app/exercises/programming/shared/code-editor/model/c import { ActivatedRoute } from '@angular/router'; import { CodeEditorContainerComponent } from 'app/exercises/programming/shared/code-editor/container/code-editor-container.component'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; -import { getUnreferencedFeedback } from 'app/exercises/shared/result/result.utils'; +import { getManualUnreferencedFeedback } from 'app/exercises/shared/result/result.utils'; import { SubmissionType } from 'app/entities/submission.model'; import { SubmissionPolicyType } from 'app/entities/submission-policy.model'; import { Course } from 'app/entities/course.model'; @@ -160,7 +160,7 @@ export class CodeEditorStudentContainerComponent implements OnInit, OnDestroy { get unreferencedFeedback(): Feedback[] { if (this.latestResult?.feedbacks) { checkSubsequentFeedbackInAssessment(this.latestResult.feedbacks); - return getUnreferencedFeedback(this.latestResult.feedbacks) ?? []; + return getManualUnreferencedFeedback(this.latestResult.feedbacks) ?? []; } return []; } diff --git a/src/main/webapp/app/exercises/shared/result/result.utils.ts b/src/main/webapp/app/exercises/shared/result/result.utils.ts index 8e2b2eb99767..85b30f694334 100644 --- a/src/main/webapp/app/exercises/shared/result/result.utils.ts +++ b/src/main/webapp/app/exercises/shared/result/result.utils.ts @@ -116,16 +116,16 @@ export const addParticipationToResult = (result: Result | undefined, participati }; /** - * searches for all unreferenced feedback in an array of feedbacks of a result + * searches for all manual unreferenced feedback in an array of feedbacks of a result * @param feedbacks the feedback of a result * @returns an array with the unreferenced feedback of the result */ -export const getUnreferencedFeedback = (feedbacks: Feedback[] | undefined): Feedback[] | undefined => { +export const getManualUnreferencedFeedback = (feedbacks: Feedback[] | undefined): Feedback[] | undefined => { return feedbacks ? feedbacks.filter((feedbackElement) => !feedbackElement.reference && feedbackElement.type === FeedbackType.MANUAL_UNREFERENCED) : undefined; }; /** - * searches for all unreferenced feedback of type AUTOMATIC in an array of feedbacks of a result + * searches for all automatic unreferenced feedback in an array of feedbacks of a result * @param feedbacks the feedback of a result * @returns an array with the unreferenced feedback of the result */ diff --git a/src/main/webapp/app/exercises/text/participate/text-editor.component.ts b/src/main/webapp/app/exercises/text/participate/text-editor.component.ts index f45eae358ac0..7e556f44aeac 100644 --- a/src/main/webapp/app/exercises/text/participate/text-editor.component.ts +++ b/src/main/webapp/app/exercises/text/participate/text-editor.component.ts @@ -20,7 +20,7 @@ import { TextSubmission } from 'app/entities/text/text-submission.model'; import { StringCountService } from 'app/exercises/text/participate/string-count.service'; import { AccountService } from 'app/core/auth/account.service'; import { getFirstResultWithComplaint, getLatestSubmissionResult, setLatestSubmissionResult } from 'app/entities/submission.model'; -import { getUnreferencedFeedback, isAthenaAIResult } from 'app/exercises/shared/result/result.utils'; +import { getManualUnreferencedFeedback, isAthenaAIResult } from 'app/exercises/shared/result/result.utils'; import { onError } from 'app/shared/util/global.utils'; import { Course } from 'app/entities/course.model'; import { getCourseFromExercise } from 'app/entities/exercise.model'; @@ -312,7 +312,7 @@ export class TextEditorComponent implements OnInit, OnDestroy, ComponentCanDeact * Check whether or not a result exists and if, returns the unreferenced feedback of it */ get unreferencedFeedback(): Feedback[] | undefined { - return this.result ? getUnreferencedFeedback(this.result.feedbacks) : undefined; + return this.result ? getManualUnreferencedFeedback(this.result.feedbacks) : undefined; } get wordCount(): number { diff --git a/src/test/javascript/spec/component/utils/result.utils.spec.ts b/src/test/javascript/spec/component/utils/result.utils.spec.ts index d8c0a7f4c0e4..ef15c7735b38 100644 --- a/src/test/javascript/spec/component/utils/result.utils.spec.ts +++ b/src/test/javascript/spec/component/utils/result.utils.spec.ts @@ -1,9 +1,9 @@ import { ResultTemplateStatus, breakCircularResultBackReferences, + getManualUnreferencedFeedback, getResultIconClass, getTextColorClass, - getUnreferencedFeedback, isOnlyCompilationTested, } from 'app/exercises/shared/result/result.utils'; import { Feedback, FeedbackType, STATIC_CODE_ANALYSIS_FEEDBACK_IDENTIFIER } from 'app/entities/feedback.model'; @@ -20,7 +20,7 @@ import dayjs from 'dayjs/esm'; describe('ResultUtils', () => { it('should filter out all non unreferenced feedbacks', () => { const feedbacks = [{ reference: 'foo' }, { reference: 'foo', type: FeedbackType.MANUAL_UNREFERENCED }, { type: FeedbackType.MANUAL_UNREFERENCED }, {}]; - const unreferencedFeedbacks = getUnreferencedFeedback(feedbacks); + const unreferencedFeedbacks = getManualUnreferencedFeedback(feedbacks); expect(unreferencedFeedbacks).toEqual([{ type: FeedbackType.MANUAL_UNREFERENCED }]); }); From e285f5ba63e33b32fde3deb9aea50ca3e5cf3627 Mon Sep 17 00:00:00 2001 From: LeonWehrhahn Date: Thu, 9 Jan 2025 18:50:11 +0100 Subject: [PATCH 3/5] Update tests --- .../exercise/participation/ParticipationIntegrationTest.java | 2 +- .../modeling-submission/modeling-submission.component.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/de/tum/cit/aet/artemis/exercise/participation/ParticipationIntegrationTest.java b/src/test/java/de/tum/cit/aet/artemis/exercise/participation/ParticipationIntegrationTest.java index bbe46c5b9b19..a2ee371bde2f 100644 --- a/src/test/java/de/tum/cit/aet/artemis/exercise/participation/ParticipationIntegrationTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/exercise/participation/ParticipationIntegrationTest.java @@ -802,7 +802,7 @@ void requestModelingFeedbackSuccess_withAthenaFailure() throws Exception { request.putWithResponseBody("/api/exercises/" + modelingExercise.getId() + "/request-feedback", null, StudentParticipation.class, HttpStatus.OK); - verify(resultWebsocketService, timeout(2000).times(1)).broadcastNewResult(any(), resultCaptor.capture()); + verify(resultWebsocketService, timeout(2000).times(2)).broadcastNewResult(any(), resultCaptor.capture()); Result invokedModelingResult = resultCaptor.getAllValues().getFirst(); assertThat(invokedModelingResult).isNotNull(); diff --git a/src/test/javascript/spec/component/modeling-submission/modeling-submission.component.spec.ts b/src/test/javascript/spec/component/modeling-submission/modeling-submission.component.spec.ts index 5117ae0429b7..603e093efca5 100644 --- a/src/test/javascript/spec/component/modeling-submission/modeling-submission.component.spec.ts +++ b/src/test/javascript/spec/component/modeling-submission/modeling-submission.component.spec.ts @@ -706,7 +706,7 @@ describe('ModelingSubmissionComponent', () => { detailText: 'feedback1', credits: 1, gradingInstruction, - type: FeedbackType.MANUAL_UNREFERENCED, + type: FeedbackType.AUTOMATIC, } as Feedback, { id: 2, From dc58d1c8858734ee97de382c5a395e7b0467e387 Mon Sep 17 00:00:00 2001 From: LeonWehrhahn Date: Thu, 9 Jan 2025 19:00:13 +0100 Subject: [PATCH 4/5] Update modeling submission test to inlcude correct feedback type --- .../modeling-submission-team.component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/javascript/spec/component/modeling-submission/modeling-submission-team.component.spec.ts b/src/test/javascript/spec/component/modeling-submission/modeling-submission-team.component.spec.ts index 1ebae9d40337..2a1eeea28e7d 100644 --- a/src/test/javascript/spec/component/modeling-submission/modeling-submission-team.component.spec.ts +++ b/src/test/javascript/spec/component/modeling-submission/modeling-submission-team.component.spec.ts @@ -505,7 +505,7 @@ describe('ModelingSubmissionComponent', () => { detailText: 'feedback1', credits: 1, gradingInstruction, - type: FeedbackType.MANUAL_UNREFERENCED, + type: FeedbackType.AUTOMATIC, } as Feedback, { id: 2, From 1846a52dda998317412007f9bc32c8bc4cb4845c Mon Sep 17 00:00:00 2001 From: LeonWehrhahn Date: Sat, 11 Jan 2025 18:18:34 +0100 Subject: [PATCH 5/5] Add feedback filtering tests to include automatic unreferenced feedback test --- .../spec/component/utils/result.utils.spec.ts | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/test/javascript/spec/component/utils/result.utils.spec.ts b/src/test/javascript/spec/component/utils/result.utils.spec.ts index ef15c7735b38..9b4463b3c353 100644 --- a/src/test/javascript/spec/component/utils/result.utils.spec.ts +++ b/src/test/javascript/spec/component/utils/result.utils.spec.ts @@ -1,6 +1,7 @@ import { ResultTemplateStatus, breakCircularResultBackReferences, + getAutomaticUnreferencedFeedback, getManualUnreferencedFeedback, getResultIconClass, getTextColorClass, @@ -18,12 +19,30 @@ import { Result } from 'app/entities/result.model'; import dayjs from 'dayjs/esm'; describe('ResultUtils', () => { - it('should filter out all non unreferenced feedbacks', () => { - const feedbacks = [{ reference: 'foo' }, { reference: 'foo', type: FeedbackType.MANUAL_UNREFERENCED }, { type: FeedbackType.MANUAL_UNREFERENCED }, {}]; + it('should filter out all non unreferenced feedbacks that do not have type MANUAL_UNREFERENCED', () => { + const feedbacks = [ + { reference: 'foo' }, + { reference: 'foo', type: FeedbackType.MANUAL_UNREFERENCED }, + { type: FeedbackType.AUTOMATIC }, + { type: FeedbackType.MANUAL_UNREFERENCED }, + {}, + ]; const unreferencedFeedbacks = getManualUnreferencedFeedback(feedbacks); expect(unreferencedFeedbacks).toEqual([{ type: FeedbackType.MANUAL_UNREFERENCED }]); }); + it('should filter out all non unreferenced feedbacks that do not have type AUTOMATIC', () => { + const feedbacks = [ + { reference: 'foo' }, + { reference: 'foo', type: FeedbackType.AUTOMATIC }, + { type: FeedbackType.AUTOMATIC }, + { type: FeedbackType.MANUAL_UNREFERENCED }, + {}, + ]; + const unreferencedFeedbacks = getAutomaticUnreferencedFeedback(feedbacks); + expect(unreferencedFeedbacks).toEqual([{ type: FeedbackType.AUTOMATIC }]); + }); + it.each([ { result: {