Skip to main content
Glama
compliance-report.mapper.test.ts9.62 kB
/** * @fileoverview Tests for ComplianceReportMapper */ import { describe, it, expect } from 'vitest'; import { ComplianceReportMapper } from '../compliance-report.mapper.js'; import { ComplianceReport as ApiComplianceReport } from '../../../deepsource.js'; import { ReportType } from '../../../types/report-types.js'; import { ComplianceReport } from '../../../domain/aggregates/compliance-report/compliance-report.aggregate.js'; import { IssueCount } from '../../../domain/value-objects/issue-count.js'; describe('ComplianceReportMapper', () => { const mockApiReport: ApiComplianceReport = { key: ReportType.OWASP_TOP_10, title: 'OWASP Top 10', currentValue: 85, status: 'READY', securityIssueStats: [ { key: 'A01', title: 'A01: Broken Access Control', occurrence: { critical: 2, major: 5, minor: 3, total: 11, }, }, { key: 'A02', title: 'A02: Cryptographic Failures', occurrence: { critical: 0, major: 1, minor: 4, total: 7, }, }, { key: 'A03', title: 'A03: Injection', occurrence: { critical: 1, major: 0, minor: 0, total: 1, }, }, ], trends: [], }; describe('toDomain', () => { it('should map API compliance report to domain aggregate', () => { const projectKey = 'test-project'; const repositoryId = 'repo-123'; const report = ComplianceReportMapper.toDomain(mockApiReport, projectKey, repositoryId); expect(report).toBeInstanceOf(ComplianceReport); expect(report.projectKey).toBe(projectKey); expect(report.repositoryId).toBe(repositoryId); expect(report.reportType).toBe(ReportType.OWASP_TOP_10); expect(report.categories).toHaveLength(3); }); it('should map categories correctly', () => { const report = ComplianceReportMapper.toDomain(mockApiReport, 'test-project', 'repo-123'); const categories = report.categories; expect(categories[0].name).toBe('A01: Broken Access Control'); expect(categories[0].severity).toBe('CRITICAL'); expect(categories[0].issueCount.count).toBe(11); // 2+5+3+1 expect(categories[1].name).toBe('A02: Cryptographic Failures'); expect(categories[1].severity).toBe('MAJOR'); // Highest severity present expect(categories[1].issueCount.count).toBe(7); // 0+1+4+2 expect(categories[2].name).toBe('A03: Injection'); expect(categories[2].severity).toBe('CRITICAL'); expect(categories[2].issueCount.count).toBe(1); // 1+0+0+0 }); it('should handle empty security issue stats', () => { const emptyReport = { ...mockApiReport, securityIssueStats: [], }; const report = ComplianceReportMapper.toDomain(emptyReport, 'test-project', 'repo-123'); expect(report.categories).toHaveLength(0); }); }); describe('mapStatus', () => { it('should map API status to domain status', () => { expect(ComplianceReportMapper.mapStatus('READY')).toBe('READY'); expect(ComplianceReportMapper.mapStatus('COMPLETED')).toBe('READY'); expect(ComplianceReportMapper.mapStatus('GENERATING')).toBe('GENERATING'); expect(ComplianceReportMapper.mapStatus('PENDING')).toBe('GENERATING'); expect(ComplianceReportMapper.mapStatus('ERROR')).toBe('ERROR'); expect(ComplianceReportMapper.mapStatus('FAILED')).toBe('ERROR'); }); it('should default to PENDING for unknown status', () => { expect(ComplianceReportMapper.mapStatus('UNKNOWN')).toBe('PENDING'); expect(ComplianceReportMapper.mapStatus(undefined)).toBe('PENDING'); }); }); describe('mapHighestSeverity', () => { it('should return CRITICAL when critical issues present', () => { const occurrence = { critical: 1, major: 5, minor: 3, total: 9 }; expect(ComplianceReportMapper.mapHighestSeverity(occurrence)).toBe('CRITICAL'); }); it('should return MAJOR when no critical but major issues present', () => { const occurrence = { critical: 0, major: 2, minor: 5, total: 7 }; expect(ComplianceReportMapper.mapHighestSeverity(occurrence)).toBe('MAJOR'); }); it('should return MINOR when no critical/major but minor issues present', () => { const occurrence = { critical: 0, major: 0, minor: 3, total: 3 }; expect(ComplianceReportMapper.mapHighestSeverity(occurrence)).toBe('MINOR'); }); it('should return INFO when no specific severity issues present', () => { const occurrence = { critical: 0, major: 0, minor: 0, total: 2 }; expect(ComplianceReportMapper.mapHighestSeverity(occurrence)).toBe('INFO'); }); it('should return INFO when no issues present', () => { const occurrence = { critical: 0, major: 0, minor: 0, total: 0 }; expect(ComplianceReportMapper.mapHighestSeverity(occurrence)).toBe('INFO'); }); }); describe('toPersistence', () => { it('should map domain aggregate to persistence format', () => { const report = ComplianceReportMapper.toDomain(mockApiReport, 'test-project', 'repo-123'); const persistence = ComplianceReportMapper.toPersistence(report); expect(persistence.id).toBe(report.id); expect(persistence.projectKey).toBe('test-project'); expect(persistence.repositoryId).toBe('repo-123'); expect(persistence.reportType).toBe(ReportType.OWASP_TOP_10); expect(persistence.categories).toEqual(report.categories); expect(persistence.generatedAt).toBeInstanceOf(Date); expect(persistence.lastUpdated).toBeInstanceOf(Date); }); }); describe('toDomainFromList', () => { it('should map multiple API reports to domain aggregates', () => { const apiReports = [ mockApiReport, { ...mockApiReport, key: ReportType.SANS_TOP_25, title: 'SANS Top 25', securityIssueStats: [ { key: 'CWE-79', title: 'Cross-site Scripting', occurrence: { critical: 1, major: 2, minor: 1, total: 4, }, }, ], }, ]; const reports = ComplianceReportMapper.toDomainFromList( apiReports, 'test-project', 'repo-123' ); expect(reports).toHaveLength(2); expect(reports[0].reportType).toBe(ReportType.OWASP_TOP_10); expect(reports[1].reportType).toBe(ReportType.SANS_TOP_25); expect(reports[1].categories).toHaveLength(1); }); it('should handle empty reports list', () => { const reports = ComplianceReportMapper.toDomainFromList([], 'test-project', 'repo-123'); expect(reports).toEqual([]); }); }); describe('createCategoryFromStat', () => { it('should create a compliance category from security issue stat', () => { const stat = { key: 'A01', title: 'Broken Access Control', occurrence: { critical: 2, major: 3, minor: 1, total: 6, }, }; const category = ComplianceReportMapper.createCategoryFromStat(stat, ReportType.OWASP_TOP_10); expect(category.name).toBe('Broken Access Control'); expect(category.description).toBe('OWASP_TOP_10 category: A01'); expect(category.issueCount.count).toBe(6); // 2+3+1+0 expect(category.nonCompliant.count).toBe(6); expect(category.compliant.count).toBe(0); expect(category.severity).toBe('CRITICAL'); }); }); describe('estimateComplianceScore', () => { it('should return 100 for empty categories', () => { const score = ComplianceReportMapper.estimateComplianceScore([]); expect(score).toBe(100); }); it('should calculate score based on severity and issue counts', () => { const categories = [ { name: 'Test Category 1', description: 'Test', compliant: IssueCount.create(0), nonCompliant: IssueCount.create(5), issueCount: IssueCount.create(5), severity: 'CRITICAL' as const, }, { name: 'Test Category 2', description: 'Test', compliant: IssueCount.create(0), nonCompliant: IssueCount.create(3), issueCount: IssueCount.create(3), severity: 'MAJOR' as const, }, ]; const score = ComplianceReportMapper.estimateComplianceScore(categories); // Expected: 100 - (1 * 20 + 1 * 10 + 8 * 2) = 100 - 46 = 54 expect(score).toBe(54); }); it('should not go below 0', () => { const categories = Array(10).fill({ name: 'Critical Category', description: 'Test', compliant: IssueCount.create(0), nonCompliant: IssueCount.create(10), issueCount: IssueCount.create(10), severity: 'CRITICAL' as const, }); const score = ComplianceReportMapper.estimateComplianceScore(categories); expect(score).toBe(0); }); it('should not go above 100', () => { const categories = [ { name: 'Minor Category', description: 'Test', compliant: IssueCount.create(0), nonCompliant: IssueCount.create(1), issueCount: IssueCount.create(1), severity: 'INFO' as const, }, ]; const score = ComplianceReportMapper.estimateComplianceScore(categories); expect(score).toBe(98); // 100 - 2 = 98 }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sapientpants/deepsource-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server