Skip to content

Commit f291d86

Browse files
committed
Fix trace generation for landscapes with one class
1 parent 8405a9e commit f291d86

3 files changed

Lines changed: 116 additions & 2 deletions

File tree

src/backend/generation.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,9 @@ export function generateFakeTrace(apps: Array<FakeApp>, params: TraceGenerationP
594594
visitedClasses.delete(head[0]);
595595
classStack[classStack.length - 1][1].children.push(head[1]);
596596
previousClass = classStack[classStack.length - 1][0];
597+
} else {
598+
// Cannot reduce stack further, break out of the loop
599+
break;
597600
}
598601
continue;
599602
}
@@ -616,6 +619,9 @@ export function generateFakeTrace(apps: Array<FakeApp>, params: TraceGenerationP
616619
visitedClasses.delete(head[0]);
617620
classStack[classStack.length - 1][1].children.push(head[1]);
618621
previousClass = classStack[classStack.length - 1][0];
622+
} else {
623+
// Cannot reduce stack further, break out of the loop
624+
break;
619625
}
620626
continue;
621627
}

tests/backend/integration/trace-generation.test.ts

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { readFileSync } from 'fs';
22
import { join } from 'path';
33
import { beforeEach, describe, expect, it } from 'vitest';
44
import { CommunicationStyle, generateFakeTrace, TraceGenerationParameters } from '../../../src/backend/generation';
5-
import { FakeApp } from '../../../src/backend/shared/types';
5+
import { FakeApp, FakeClass, FakePackage } from '../../../src/backend/shared/types';
66
import { reconstructParentReferences } from '../../../src/backend/utils/landscape.utils';
77

88
describe('Trace Generation Integration', () => {
@@ -469,4 +469,112 @@ describe('Trace Generation Integration', () => {
469469
expect(names1).not.toEqual(names2);
470470
});
471471
});
472+
473+
describe('Single Class Landscape', () => {
474+
it('should handle single class with multiple methods without hanging', () => {
475+
// Create a simple landscape with one class and two methods
476+
const rootPackage: FakePackage = {
477+
name: 'org',
478+
classes: [],
479+
subpackages: [],
480+
};
481+
482+
const appPackage: FakePackage = {
483+
name: 'testapp',
484+
classes: [],
485+
subpackages: [],
486+
parent: rootPackage,
487+
};
488+
489+
rootPackage.subpackages.push(appPackage);
490+
491+
const testClass: FakeClass = {
492+
identifier: 'TestClass',
493+
methods: ['method1', 'method2'],
494+
parent: appPackage,
495+
parentAppName: 'test-app',
496+
};
497+
498+
appPackage.classes.push(testClass);
499+
500+
const testApp: FakeApp = {
501+
name: 'test-app',
502+
rootPackages: [rootPackage],
503+
entryPoint: testClass,
504+
classes: [testClass],
505+
packages: [rootPackage, appPackage],
506+
methods: ['method1', 'method2'],
507+
};
508+
509+
const params: TraceGenerationParameters = {
510+
duration: 1000,
511+
callCount: 5,
512+
maxConnectionDepth: 3,
513+
communicationStyle: CommunicationStyle.TRUE_RANDOM,
514+
allowCyclicCalls: false,
515+
seed: 12345,
516+
};
517+
518+
// This should complete without hanging
519+
const trace = generateFakeTrace([testApp], params);
520+
521+
// Verify trace was generated
522+
expect(trace).toBeDefined();
523+
expect(trace.length).toBe(1);
524+
expect(trace[0].name).toContain('TestClass');
525+
});
526+
527+
it('should handle single class with allowCyclicCalls enabled', () => {
528+
const rootPackage: FakePackage = {
529+
name: 'org',
530+
classes: [],
531+
subpackages: [],
532+
};
533+
534+
const appPackage: FakePackage = {
535+
name: 'testapp',
536+
classes: [],
537+
subpackages: [],
538+
parent: rootPackage,
539+
};
540+
541+
rootPackage.subpackages.push(appPackage);
542+
543+
const testClass: FakeClass = {
544+
identifier: 'TestClass',
545+
methods: ['method1', 'method2'],
546+
parent: appPackage,
547+
parentAppName: 'test-app',
548+
};
549+
550+
appPackage.classes.push(testClass);
551+
552+
const testApp: FakeApp = {
553+
name: 'test-app',
554+
rootPackages: [rootPackage],
555+
entryPoint: testClass,
556+
classes: [testClass],
557+
packages: [rootPackage, appPackage],
558+
methods: ['method1', 'method2'],
559+
};
560+
561+
const params: TraceGenerationParameters = {
562+
duration: 1000,
563+
callCount: 5,
564+
maxConnectionDepth: 3,
565+
communicationStyle: CommunicationStyle.TRUE_RANDOM,
566+
allowCyclicCalls: true,
567+
seed: 54321,
568+
};
569+
570+
const trace = generateFakeTrace([testApp], params);
571+
572+
function countSpans(spans: any[]): number {
573+
return spans.length + spans.reduce((sum, span) => sum + countSpans(span.children), 0);
574+
}
575+
576+
// With cyclic calls enabled, should generate the requested number of spans
577+
expect(countSpans(trace)).toBe(6); // 1 root + 5 calls
578+
});
579+
});
472580
});

tests/frontend/LandscapeEditorDragDrop.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @vitest-environment jsdom
33
*/
44
import { describe, expect, it } from 'vitest';
5-
import { CleanedLandscape, CleanedPackage, CleanedClass } from '../../src/backend/shared/types';
5+
import { CleanedClass, CleanedLandscape, CleanedPackage } from '../../src/backend/shared/types';
66

77
describe('LandscapeEditor - Drag and Drop Move Functions', () => {
88
const createMockApp = (name: string, rootPackages?: CleanedPackage[], classes?: CleanedClass[]): CleanedLandscape => {

0 commit comments

Comments
 (0)