@elisra-devops/docgen-data-provider 1.86.0 → 1.88.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/modules/ResultDataProvider.d.ts +1 -0
- package/bin/modules/ResultDataProvider.js +130 -12
- package/bin/modules/ResultDataProvider.js.map +1 -1
- package/bin/tests/modules/ResultDataProvider.test.js +133 -1
- package/bin/tests/modules/ResultDataProvider.test.js.map +1 -1
- package/package.json +1 -1
- package/src/modules/ResultDataProvider.ts +142 -12
- package/src/tests/modules/ResultDataProvider.test.ts +153 -1
|
@@ -142,6 +142,7 @@ export default class ResultDataProvider {
|
|
|
142
142
|
private isExcludedL3L4BySapWbs;
|
|
143
143
|
private normalizeMewpRequirementCode;
|
|
144
144
|
private normalizeMewpRequirementCodeWithSuffix;
|
|
145
|
+
private formatRequirementCodesGroupedByFamily;
|
|
145
146
|
private toMewpComparableText;
|
|
146
147
|
private fetchTestPlanName;
|
|
147
148
|
/**
|
|
@@ -523,6 +523,35 @@ class ResultDataProvider {
|
|
|
523
523
|
};
|
|
524
524
|
for (const testCaseId of [...allTestCaseIds].sort((a, b) => a - b)) {
|
|
525
525
|
diagnostics.totalTestCases += 1;
|
|
526
|
+
const logList = (items, max = 12) => {
|
|
527
|
+
const values = [...items].map((item) => String(item || '').trim()).filter((item) => !!item);
|
|
528
|
+
const shown = values.slice(0, max);
|
|
529
|
+
const suffix = values.length > max ? ` ...(+${values.length - max} more)` : '';
|
|
530
|
+
return shown.join(', ') + suffix;
|
|
531
|
+
};
|
|
532
|
+
const logByFamily = (items, maxFamilies = 8, maxMembers = 10) => {
|
|
533
|
+
const map = new Map();
|
|
534
|
+
for (const item of items || []) {
|
|
535
|
+
const normalized = this.normalizeMewpRequirementCodeWithSuffix(String(item || ''));
|
|
536
|
+
if (!normalized)
|
|
537
|
+
continue;
|
|
538
|
+
const base = this.toRequirementKey(normalized) || normalized;
|
|
539
|
+
if (!map.has(base))
|
|
540
|
+
map.set(base, new Set());
|
|
541
|
+
map.get(base).add(normalized);
|
|
542
|
+
}
|
|
543
|
+
const entries = [...map.entries()]
|
|
544
|
+
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
545
|
+
.slice(0, maxFamilies)
|
|
546
|
+
.map(([base, members]) => {
|
|
547
|
+
const sortedMembers = [...members].sort((a, b) => a.localeCompare(b));
|
|
548
|
+
const shownMembers = sortedMembers.slice(0, maxMembers);
|
|
549
|
+
const membersSuffix = sortedMembers.length > maxMembers ? ` ...(+${sortedMembers.length - maxMembers} more)` : '';
|
|
550
|
+
return `${base}=[${shownMembers.join(', ')}${membersSuffix}]`;
|
|
551
|
+
});
|
|
552
|
+
const suffix = map.size > maxFamilies ? ` ...(+${map.size - maxFamilies} families)` : '';
|
|
553
|
+
return entries.join(' | ') + suffix;
|
|
554
|
+
};
|
|
526
555
|
const stepsXml = stepsXmlByTestCase.get(testCaseId) || '';
|
|
527
556
|
const parsedSteps = stepsXml && String(stepsXml).trim() !== ''
|
|
528
557
|
? await this.testStepParserHelper.parseTestSteps(stepsXml, new Map())
|
|
@@ -563,6 +592,13 @@ class ResultDataProvider {
|
|
|
563
592
|
? new Set([...linkedFullCodesRaw].filter((code) => scopedRequirementKeys.has(this.toRequirementKey(code))))
|
|
564
593
|
: linkedFullCodesRaw;
|
|
565
594
|
const linkedBaseKeys = new Set([...linkedFullCodes].map((code) => this.toRequirementKey(code)).filter((code) => !!code));
|
|
595
|
+
const mentionStepSample = mentionEntries
|
|
596
|
+
.slice(0, 8)
|
|
597
|
+
.map((entry) => `${entry.stepRef}=[${logList(entry.codes, 6)}]`)
|
|
598
|
+
.join(' | ');
|
|
599
|
+
logger_1.default.debug(`MEWP internal validation trace: testCaseId=${testCaseId} ` +
|
|
600
|
+
`mentionSteps=${mentionEntries.length} mentionStepSample='${mentionStepSample}' ` +
|
|
601
|
+
`mentionedL2ByFamily='${logByFamily(mentionedL2Only)}' linkedByFamily='${logByFamily(linkedFullCodes)}'`);
|
|
566
602
|
const mentionedCodesByBase = new Map();
|
|
567
603
|
for (const code of mentionedL2Only) {
|
|
568
604
|
const baseKey = this.toRequirementKey(code);
|
|
@@ -581,32 +617,85 @@ class ResultDataProvider {
|
|
|
581
617
|
const missingFamilyMembers = new Set();
|
|
582
618
|
for (const [baseKey, mentionedCodes] of mentionedCodesByBase.entries()) {
|
|
583
619
|
const familyCodes = requirementFamilies.get(baseKey);
|
|
620
|
+
const mentionedCodesList = [...mentionedCodes];
|
|
621
|
+
const hasBaseMention = mentionedCodesList.some((code) => !/-\d+$/.test(code));
|
|
622
|
+
const mentionedSpecificMembers = mentionedCodesList.filter((code) => /-\d+$/.test(code));
|
|
623
|
+
let familyDecision = 'no-action';
|
|
624
|
+
let familyTargetCodes = [];
|
|
625
|
+
let familyMissingCodes = [];
|
|
626
|
+
let familyLinkedCodes = [];
|
|
627
|
+
let familyAllCodes = [];
|
|
584
628
|
if (familyCodes === null || familyCodes === void 0 ? void 0 : familyCodes.size) {
|
|
585
|
-
|
|
586
|
-
|
|
629
|
+
familyAllCodes = [...familyCodes].sort((a, b) => a.localeCompare(b));
|
|
630
|
+
familyLinkedCodes = familyAllCodes.filter((code) => linkedFullCodes.has(code));
|
|
631
|
+
// Base mention ("SR0054") validates against child coverage when children exist.
|
|
632
|
+
// If no child variants exist, fallback to the single standalone requirement code.
|
|
633
|
+
if (hasBaseMention) {
|
|
634
|
+
const familyCodesList = [...familyCodes];
|
|
635
|
+
const childFamilyCodes = familyCodesList.filter((code) => /-\d+$/.test(code));
|
|
636
|
+
const targetFamilyCodes = childFamilyCodes.length > 0 ? childFamilyCodes : familyCodesList;
|
|
637
|
+
familyTargetCodes = [...targetFamilyCodes].sort((a, b) => a.localeCompare(b));
|
|
638
|
+
const missingInTargetFamily = targetFamilyCodes.filter((code) => !linkedFullCodes.has(code));
|
|
639
|
+
familyMissingCodes = [...missingInTargetFamily].sort((a, b) => a.localeCompare(b));
|
|
640
|
+
if (missingInTargetFamily.length > 0) {
|
|
641
|
+
const hasAnyLinkedInFamily = familyCodesList.some((code) => linkedFullCodes.has(code));
|
|
642
|
+
if (!hasAnyLinkedInFamily) {
|
|
643
|
+
missingBaseWhenFamilyUncovered.add(baseKey);
|
|
644
|
+
familyDecision = 'base-mentioned-family-uncovered';
|
|
645
|
+
}
|
|
646
|
+
else {
|
|
647
|
+
for (const code of missingInTargetFamily) {
|
|
648
|
+
missingFamilyMembers.add(code);
|
|
649
|
+
}
|
|
650
|
+
familyDecision = 'base-mentioned-family-partial-missing-children';
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
familyDecision = 'base-mentioned-family-fully-covered';
|
|
655
|
+
}
|
|
656
|
+
logger_1.default.debug(`MEWP internal validation family decision: testCaseId=${testCaseId} base=${baseKey} ` +
|
|
657
|
+
`mode=baseMention mentioned='${logList(mentionedCodesList)}' familyAll='${logList(familyAllCodes)}' ` +
|
|
658
|
+
`target='${logList(familyTargetCodes)}' linked='${logList(familyLinkedCodes)}' ` +
|
|
659
|
+
`missing='${logList(familyMissingCodes)}' decision=${familyDecision}`);
|
|
587
660
|
continue;
|
|
588
|
-
const linkedInFamilyCount = familyCodes.size - missingInFamily.length;
|
|
589
|
-
if (linkedInFamilyCount === 0) {
|
|
590
|
-
missingBaseWhenFamilyUncovered.add(baseKey);
|
|
591
661
|
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
662
|
+
// Specific mention ("SR0054-1") validates as exact-match only.
|
|
663
|
+
const missingSpecificMembers = [];
|
|
664
|
+
for (const code of mentionedSpecificMembers) {
|
|
665
|
+
if (!linkedFullCodes.has(code)) {
|
|
666
|
+
missingSpecificMentionedNoFamily.add(code);
|
|
667
|
+
missingSpecificMembers.push(code);
|
|
595
668
|
}
|
|
596
669
|
}
|
|
670
|
+
familyDecision =
|
|
671
|
+
missingSpecificMembers.length > 0
|
|
672
|
+
? 'specific-mentioned-exact-missing'
|
|
673
|
+
: 'specific-mentioned-exact-covered';
|
|
674
|
+
logger_1.default.debug(`MEWP internal validation family decision: testCaseId=${testCaseId} base=${baseKey} ` +
|
|
675
|
+
`mode=specificMention mentioned='${logList(mentionedCodesList)}' familyAll='${logList(familyAllCodes)}' ` +
|
|
676
|
+
`linked='${logList(familyLinkedCodes)}' missingSpecific='${logList(missingSpecificMembers)}' ` +
|
|
677
|
+
`decision=${familyDecision}`);
|
|
597
678
|
continue;
|
|
598
679
|
}
|
|
599
680
|
// Fallback path when family data is unavailable for this base key.
|
|
681
|
+
const fallbackMissingSpecific = [];
|
|
682
|
+
let fallbackBaseMissing = false;
|
|
600
683
|
for (const code of mentionedCodes) {
|
|
601
684
|
const hasSpecificSuffix = /-\d+$/.test(code);
|
|
602
685
|
if (hasSpecificSuffix) {
|
|
603
|
-
if (!linkedFullCodes.has(code))
|
|
686
|
+
if (!linkedFullCodes.has(code)) {
|
|
604
687
|
missingSpecificMentionedNoFamily.add(code);
|
|
688
|
+
fallbackMissingSpecific.push(code);
|
|
689
|
+
}
|
|
605
690
|
}
|
|
606
691
|
else if (!linkedBaseKeys.has(baseKey)) {
|
|
607
692
|
missingBaseWhenFamilyUncovered.add(baseKey);
|
|
693
|
+
fallbackBaseMissing = true;
|
|
608
694
|
}
|
|
609
695
|
}
|
|
696
|
+
logger_1.default.debug(`MEWP internal validation family decision: testCaseId=${testCaseId} base=${baseKey} ` +
|
|
697
|
+
`mode=noFamilyData mentioned='${logList(mentionedCodesList)}' linkedBasePresent=${linkedBaseKeys.has(baseKey)} ` +
|
|
698
|
+
`missingSpecific='${logList(fallbackMissingSpecific)}' missingBase=${fallbackBaseMissing}`);
|
|
610
699
|
}
|
|
611
700
|
// Direction B is family-based: if any member of a family is mentioned in Expected Result,
|
|
612
701
|
// linked members of that same family are not considered "linked but not mentioned".
|
|
@@ -661,11 +750,17 @@ class ResultDataProvider {
|
|
|
661
750
|
return String(a[0]).localeCompare(String(b[0]));
|
|
662
751
|
})
|
|
663
752
|
.map(([stepRef, requirementIds]) => {
|
|
664
|
-
const
|
|
665
|
-
return `${stepRef}: ${
|
|
753
|
+
const groupedRequirementList = this.formatRequirementCodesGroupedByFamily(requirementIds);
|
|
754
|
+
return `${stepRef}: ${groupedRequirementList}`;
|
|
666
755
|
})
|
|
667
756
|
.join('; ');
|
|
668
|
-
const linkedButNotMentioned =
|
|
757
|
+
const linkedButNotMentioned = this.formatRequirementCodesGroupedByFamily(sortedExtraLinked);
|
|
758
|
+
const rawMentionedByStepForLog = [...mentionedButNotLinkedByStep.entries()]
|
|
759
|
+
.map(([stepRef, requirementIds]) => `${stepRef}=[${logList(requirementIds, 8)}]`)
|
|
760
|
+
.join(' | ');
|
|
761
|
+
logger_1.default.debug(`MEWP internal validation grouped diagnostics: testCaseId=${testCaseId} ` +
|
|
762
|
+
`rawMentionedByStep='${rawMentionedByStepForLog}' groupedMentioned='${mentionedButNotLinked}' ` +
|
|
763
|
+
`rawLinkedOnlyByFamily='${logByFamily(sortedExtraLinked)}' groupedLinkedOnly='${linkedButNotMentioned}'`);
|
|
669
764
|
const validationStatus = mentionedButNotLinked || linkedButNotMentioned ? 'Fail' : 'Pass';
|
|
670
765
|
if (validationStatus === 'Fail')
|
|
671
766
|
diagnostics.failingRows += 1;
|
|
@@ -2254,6 +2349,29 @@ class ResultDataProvider {
|
|
|
2254
2349
|
return `SR${match[1]}-${match[2]}`;
|
|
2255
2350
|
return `SR${match[1]}`;
|
|
2256
2351
|
}
|
|
2352
|
+
formatRequirementCodesGroupedByFamily(codes) {
|
|
2353
|
+
const byBaseKey = new Map();
|
|
2354
|
+
for (const rawCode of codes || []) {
|
|
2355
|
+
const normalizedCode = this.normalizeMewpRequirementCodeWithSuffix(String(rawCode || ''));
|
|
2356
|
+
if (!normalizedCode)
|
|
2357
|
+
continue;
|
|
2358
|
+
const baseKey = this.toRequirementKey(normalizedCode) || normalizedCode;
|
|
2359
|
+
if (!byBaseKey.has(baseKey))
|
|
2360
|
+
byBaseKey.set(baseKey, new Set());
|
|
2361
|
+
byBaseKey.get(baseKey).add(normalizedCode);
|
|
2362
|
+
}
|
|
2363
|
+
if (byBaseKey.size === 0)
|
|
2364
|
+
return '';
|
|
2365
|
+
return [...byBaseKey.entries()]
|
|
2366
|
+
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
2367
|
+
.map(([baseKey, members]) => {
|
|
2368
|
+
const sortedMembers = [...members].sort((a, b) => a.localeCompare(b));
|
|
2369
|
+
if (sortedMembers.length <= 1)
|
|
2370
|
+
return sortedMembers[0];
|
|
2371
|
+
return `${baseKey}: ${sortedMembers.join(', ')}`;
|
|
2372
|
+
})
|
|
2373
|
+
.join('; ');
|
|
2374
|
+
}
|
|
2257
2375
|
toMewpComparableText(value) {
|
|
2258
2376
|
if (value === null || value === undefined)
|
|
2259
2377
|
return '';
|