Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion projects/ngx-coding-components/src/lib/translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,18 @@
"TAKE_NOT_REACHED_AS_VALUE_CHANGED": "Nicht erreicht = Wert geändert",
"TAKE_EMPTY_AS_VALID": "Leerer Antwortwert ist gültig",
"SORT": "Sortiere Werte",
"SOLVER_EXPRESSION": "Ausdruck für Solver"
"SOLVER_EXPRESSION": "Ausdruck für Solver",
"solver-test": {
"title": "Solver-Test",
"action": "Testen",
"result": "Ergebnis",
"no-sources": "Keine Quellvariable ausgewählt.",
"error-expression-missing": "Bitte einen Solver-Ausdruck eingeben.",
"error-sources-missing": "Bitte mindestens eine Quellvariable auswählen.",
"error-unselected-source": "Der Ausdruck verweist auf nicht ausgewählte Quelle(n)",
"error-invalid-value": "Bitte numerischen Testwert prüfen",
"error-evaluation": "Der Ausdruck konnte nicht ausgewertet werden. Bitte Syntax, Variablennamen und numerische Testwerte prüfen."
}
},
"processing": {
"label": "Allgemeine Parameter für die Verarbeitung der Antwort",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,45 @@ <h1 mat-dialog-title>{{ (newVariableMode ? 'varList.add' : 'derive-processing.pr
@if (data.sourceType === 'SOLVER') {
<mat-form-field>
<mat-label>{{ 'derive-processing.SOLVER_EXPRESSION' | translate }}</mat-label>
<input matInput [(ngModel)]="data.sourceParameters.solverExpression">
<input matInput [(ngModel)]="data.sourceParameters.solverExpression"
(ngModelChange)="clearSolverTestResult()">
</mat-form-field>

<section class="solver-test-area">
<div class="solver-test-header">
<div class="solver-test-title">{{ 'derive-processing.solver-test.title' | translate }}</div>
<button mat-stroked-button color="primary" type="button"
[disabled]="data.deriveSources.length < 1"
(click)="runSolverTest()">
<mat-icon>calculate</mat-icon>
{{ 'derive-processing.solver-test.action' | translate }}
</button>
</div>

@if (selectedSolverSources.length > 0) {
<div class="solver-test-values">
@for (source of selectedSolverSources; track source.id) {
<mat-form-field>
<mat-label>{{ source.label }}</mat-label>
<input matInput [(ngModel)]="solverTestValues[source.id]"
(ngModelChange)="clearSolverTestResult()">
</mat-form-field>
}
</div>
} @else {
<div class="solver-test-hint">
{{ 'derive-processing.solver-test.no-sources' | translate }}
</div>
}

@if (solverTestResult) {
<div class="solver-test-result"
[class.solver-test-result-ok]="solverTestResult.type === 'success'"
[class.solver-test-result-error]="solverTestResult.type === 'error'">
{{ solverTestResult.message }}
</div>
}
</section>
}
</div>
</mat-dialog-content>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
import { SourceType, VariableSourceParameters, SourceProcessingType } from
'@iqbspecs/coding-scheme/coding-scheme.interface';
import { TranslateService } from '@ngx-translate/core';
import { EditSourceParametersDialog, EditSourceParametersDialogData } from './edit-source-parameters-dialog.component';
import { SchemerService } from '../../services/schemer.service';

describe('EditSourceParametersDialog', () => {
const solverRef = (variableName: string): string => `\${${variableName}}`;

const translations: Record<string, string> = {
'derive-processing.solver-test.result': 'Ergebnis',
'derive-processing.solver-test.error-expression-missing': 'Bitte einen Solver-Ausdruck eingeben.',
'derive-processing.solver-test.error-sources-missing': 'Bitte mindestens eine Quellvariable auswählen.',
'derive-processing.solver-test.error-unselected-source': 'Der Ausdruck verweist auf nicht ausgewählte Quelle(n)',
'derive-processing.solver-test.error-invalid-value': 'Bitte numerischen Testwert prüfen',
'derive-processing.solver-test.error-evaluation': 'Der Ausdruck konnte nicht ausgewertet werden.'
};

const createDialog = (options: {
selfId?: string;
selfAlias?: string;
Expand All @@ -21,27 +33,42 @@ describe('EditSourceParametersDialog', () => {
}

const data: EditSourceParametersDialogData = {
selfId: options.selfId ?? 'v1',
selfId: options.selfId ?? 'd1',
selfAlias: options.selfAlias ?? 'V1',
sourceType: (options.sourceType as SourceType) ?? 'COPY_VALUE',
sourceParameters: baseSourceParameters as VariableSourceParameters,
deriveSources: [...(options.deriveSources ?? [])]
};

const hasCodingSchemeOverride = Object.prototype.hasOwnProperty.call(options, 'codingScheme');
const codingScheme = hasCodingSchemeOverride ?
options.codingScheme :
{
variableCodings: [
{ id: 'v1', alias: 'V1', sourceType: 'BASE' },
{ id: 'v2', alias: 'V2', sourceType: 'DERIVE' },
{ id: 'v3', alias: 'V3', sourceType: 'BASE_NO_VALUE' }
]
};
const schemerService = {
codingScheme: hasCodingSchemeOverride ?
options.codingScheme :
{
variableCodings: [
{ id: 'v1', alias: 'V1', sourceType: 'BASE' },
{ id: 'v2', alias: 'V2', sourceType: 'DERIVE' },
{ id: 'v3', alias: 'V3', sourceType: 'BASE_NO_VALUE' }
]
}
codingScheme,
getVariableAliasById: (varId: string) => {
const variableCoding = codingScheme?.variableCodings.find(
variable => (variable as { id: string }).id === varId
) as { id: string; alias?: string } | undefined;
return variableCoding?.alias || variableCoding?.id || '?';
}
} as unknown as SchemerService;

return new EditSourceParametersDialog(data, schemerService);
const translateService = {
instant: (key: string) => translations[key] || key
} as unknown as TranslateService;

return new EditSourceParametersDialog(
data,
schemerService,
translateService
);
};

it('should set newVariableMode when selfId is missing', () => {
Expand Down Expand Up @@ -117,5 +144,98 @@ describe('EditSourceParametersDialog', () => {
dialog.toggleAllSelection();

expect(dialog.selectedSources.value).toEqual(['v2']);
expect(dialog.data.deriveSources).toEqual(['v2']);
});

it('runSolverTest should evaluate the current expression with test values', () => {
const dialog = createDialog({
selfAlias: 'D',
sourceType: 'SOLVER',
sourceParameters: {
solverExpression: `${solverRef('V1')} + ${solverRef('V2')}`
},
deriveSources: ['v1', 'v2']
});

dialog.solverTestValues['v1'] = '2';
dialog.solverTestValues['v2'] = '3';
dialog.runSolverTest();

expect(dialog.solverTestResult).toEqual({
type: 'success',
message: 'Ergebnis: 5'
});
});

it('runSolverTest should show missing selected sources for referenced variables', () => {
const dialog = createDialog({
selfAlias: 'D',
sourceType: 'SOLVER',
sourceParameters: {
solverExpression: `${solverRef('V1')} + ${solverRef('V2')}`
},
deriveSources: ['v1']
});

dialog.solverTestValues['v1'] = '2';
dialog.runSolverTest();

expect(dialog.solverTestResult?.type).toBe('error');
expect(dialog.solverTestResult?.message).toContain(
'Der Ausdruck verweist auf nicht ausgewählte Quelle(n)'
);
expect(dialog.solverTestResult?.message).toContain('V2');
});

it('runSolverTest should report non-numeric test values', () => {
const dialog = createDialog({
selfAlias: 'D',
sourceType: 'SOLVER',
sourceParameters: { solverExpression: `${solverRef('V1')} + 1` },
deriveSources: ['v1']
});

dialog.solverTestValues['v1'] = 'abc';
dialog.runSolverTest();

expect(dialog.solverTestResult?.type).toBe('error');
expect(dialog.solverTestResult?.message).toContain(
'Bitte numerischen Testwert prüfen'
);
expect(dialog.solverTestResult?.message).toContain('V1');
});

it('runSolverTest should report syntax and evaluation errors', () => {
const dialog = createDialog({
selfAlias: 'D',
sourceType: 'SOLVER',
sourceParameters: { solverExpression: `${solverRef('V1')} +` },
deriveSources: ['v1']
});

dialog.solverTestValues['v1'] = '2';
dialog.runSolverTest();

expect(dialog.solverTestResult).toEqual({
type: 'error',
message: 'Der Ausdruck konnte nicht ausgewertet werden.'
});
});

it('updateDeriveSources should keep solver test values aligned with selected sources', () => {
const dialog = createDialog({
selfAlias: 'D',
sourceType: 'SOLVER',
deriveSources: ['v1']
});

dialog.solverTestValues['v1'] = '4';
dialog.solverTestResult = { type: 'success', message: 'Ergebnis: 4' };
dialog.selectedSources.setValue(['v2']);
dialog.updateDeriveSources();

expect(dialog.data.deriveSources).toEqual(['v2']);
expect(dialog.solverTestValues).toEqual({ v2: '' });
expect(dialog.solverTestResult).toBeNull();
});
});
Loading
Loading