Skip to content

Commit cf2e75c

Browse files
committed
testing and refinement
1 parent 3b7cbf9 commit cf2e75c

File tree

4 files changed

+101
-191
lines changed

4 files changed

+101
-191
lines changed

src/client/testing/testController/common/projectAdapter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ import { PythonEnvironment, PythonProject } from '../../../envExt/types';
1515
/**
1616
* Represents a single Python project with its own test infrastructure.
1717
* A project is defined as a combination of a Python executable + URI (folder/file).
18+
* Projects are keyed by projectUri.toString()
1819
*/
1920
export interface ProjectAdapter {
2021
// === IDENTITY ===
2122
/**
22-
* Unique identifier for this project, generated by hashing the PythonProject object.
23+
* Project identifier, which is the string representation of the project URI.
2324
*/
2425
projectId: string;
2526

src/client/testing/testController/common/projectUtils.ts

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,25 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
import * as crypto from 'crypto';
5-
import { PythonProject } from '../../../envExt/types';
4+
import { Uri } from 'vscode';
65

76
/**
87
* Separator used to scope test IDs to a specific project.
98
* Format: {projectId}{SEPARATOR}{testPath}
10-
* Example: "project-abc123def456::test_file.py::test_name"
9+
* Example: "file:///workspace/project||test_file.py::test_name"
1110
*/
12-
export const PROJECT_ID_SEPARATOR = '::';
11+
export const PROJECT_ID_SEPARATOR = '||';
1312

1413
/**
15-
* Generates a unique project ID by hashing the PythonProject object.
16-
* This ensures consistent IDs across extension reloads for the same project.
17-
* Uses 16 characters of the hash to reduce collision probability.
14+
* Gets the project ID from a project URI.
15+
* The project ID is simply the string representation of the URI, matching how
16+
* the Python Environments extension stores projects in Map<string, PythonProject>.
1817
*
19-
* @param pythonProject The PythonProject object from the environment API
20-
* @returns A unique string identifier for the project
18+
* @param projectUri The project URI
19+
* @returns The project ID (URI as string)
2120
*/
22-
export function generateProjectId(pythonProject: PythonProject): string {
23-
// Create a stable string representation of the project
24-
// Use URI as the primary identifier (stable across renames)
25-
const projectString = JSON.stringify({
26-
uri: pythonProject.uri.toString(),
27-
name: pythonProject.name,
28-
});
29-
30-
// Generate a hash to create a shorter, unique ID
31-
// Using 16 chars (64 bits) instead of 12 (48 bits) for better collision resistance
32-
const hash = crypto.createHash('sha256').update(projectString).digest('hex');
33-
return `project-${hash.substring(0, 16)}`;
21+
export function getProjectId(projectUri: Uri): string {
22+
return projectUri.toString();
3423
}
3524

3625
/**

src/client/testing/testController/controller.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ import { PythonResultResolver } from './common/resultResolver';
5353
import { onDidSaveTextDocument } from '../../common/vscodeApis/workspaceApis';
5454
import { IEnvironmentVariablesProvider } from '../../common/variables/types';
5555
import { ProjectAdapter } from './common/projectAdapter';
56-
import { generateProjectId, createProjectDisplayName } from './common/projectUtils';
56+
import { getProjectId, createProjectDisplayName } from './common/projectUtils';
5757
import { PythonProject, PythonEnvironment } from '../../envExt/types';
5858
import { getEnvExtApi, useEnvExtension } from '../../envExt/api.internal';
5959

@@ -66,11 +66,19 @@ type TriggerType = EventPropertyType[TriggerKeyType];
6666
export class PythonTestController implements ITestController, IExtensionSingleActivationService {
6767
public readonly supportedWorkspaceTypes = { untrustedWorkspace: false, virtualWorkspace: false };
6868

69+
/**
70+
* Feature flag for project-based testing.
71+
* Set to true to enable multi-project testing support (Phases 2-4 must be complete).
72+
* Default: false (use legacy single-workspace mode)
73+
*/
74+
private readonly useProjectBasedTesting = false;
75+
6976
// Legacy: Single workspace test adapter per workspace (backward compatibility)
7077
private readonly testAdapters: Map<Uri, WorkspaceTestAdapter> = new Map();
7178

7279
// === NEW: PROJECT-BASED STATE ===
73-
// Map of workspace URI -> Map of project ID -> ProjectAdapter
80+
// Map of workspace URI -> Map of project URI string -> ProjectAdapter
81+
// Note: Project URI strings match Python Environments extension's Map<string, PythonProject> keys
7482
private readonly workspaceProjects: Map<Uri, Map<string, ProjectAdapter>> = new Map();
7583

7684
// TODO: Phase 3-4 - Add these maps when implementing discovery and execution:
@@ -227,8 +235,8 @@ export class PythonTestController implements ITestController, IExtensionSingleAc
227235
public async activate(): Promise<void> {
228236
const workspaces: readonly WorkspaceFolder[] = this.workspaceService.workspaceFolders || [];
229237

230-
// Try to use project-based testing if environment extension is enabled
231-
if (useEnvExtension()) {
238+
// Try to use project-based testing if feature flag is enabled AND environment extension is available
239+
if (this.useProjectBasedTesting && useEnvExtension()) {
232240
traceInfo('[test-by-project] Activating project-based testing mode');
233241

234242
// Use Promise.allSettled to allow partial success in multi-root workspaces
@@ -239,10 +247,11 @@ export class PythonTestController implements ITestController, IExtensionSingleAc
239247
// Discover projects in this workspace
240248
const projects = await this.discoverWorkspaceProjects(workspace.uri);
241249

242-
// Create map for this workspace
250+
// Create map for this workspace, keyed by project URI (matches Python Environments extension)
243251
const projectsMap = new Map<string, ProjectAdapter>();
244252
projects.forEach((project) => {
245-
projectsMap.set(project.projectId, project);
253+
const projectKey = getProjectId(project.projectUri);
254+
projectsMap.set(projectKey, project);
246255
});
247256

248257
traceInfo(
@@ -374,8 +383,8 @@ export class PythonTestController implements ITestController, IExtensionSingleAc
374383
traceInfo(
375384
`[test-by-project] Creating project adapter for: ${pythonProject.name} at ${pythonProject.uri.fsPath}`,
376385
);
377-
// Generate unique project ID
378-
const projectId = generateProjectId(pythonProject);
386+
// Use project URI as the project ID (no hashing needed)
387+
const projectId = getProjectId(pythonProject.uri);
379388

380389
// Resolve the Python environment
381390
const envExtApi = await getEnvExtApi();
@@ -456,8 +465,8 @@ export class PythonTestController implements ITestController, IExtensionSingleAc
456465
uri: workspaceUri,
457466
};
458467

459-
// Use workspace URI as project ID for default project
460-
const projectId = `default-${workspaceUri.fsPath}`;
468+
// Use workspace URI as the project ID
469+
const projectId = getProjectId(workspaceUri);
461470

462471
return {
463472
projectId,

0 commit comments

Comments
 (0)