<commit_before>import * as _ from "lodash";
import * as path from "path";
import * as vs from "vscode";
import { getChannel } from "../commands/channels";
import { extensionPath } from "../extension";
import { fsPath } from "../utils";
import { DoneNotification, ErrorNotification, Group, GroupNotification, PrintNotification, Suite, SuiteNotification, Test, TestDoneNotification, TestStartNotification } from "./test_protocol";

const DART_TEST_SUITE_NODE = "dart-code:testSuiteNode";
const DART_TEST_GROUP_NODE = "dart-code:testGroupNode";
const DART_TEST_TEST_NODE = "dart-code:testTestNode";

const suites: { [key: string]: SuiteData } = {};

export class TestResultsProvider implements vs.Disposable, vs.TreeDataProvider<object> {
	private disposables: vs.Disposable[] = [];
	private onDidChangeTreeDataEmitter: vs.EventEmitter<vs.TreeItem | undefined> = new vs.EventEmitter<vs.TreeItem | undefined>();
	public readonly onDidChangeTreeData: vs.Event<vs.TreeItem | undefined> = this.onDidChangeTreeDataEmitter.event;
	private onDidStartTestsEmitter: vs.EventEmitter<vs.TreeItem | undefined> = new vs.EventEmitter<vs.TreeItem | undefined>();
	public readonly onDidStartTests: vs.Event<vs.TreeItem | undefined> = this.onDidStartTestsEmitter.event;

	// Set this flag we know when a new run starts so we can show the tree; however
	// we can't show it until we render a node (we can only call reveal on a node) so
	// we need to delay this until the suite starts.
	public static shouldShowTreeOnNextSuiteStart = true;

	constructor() {
		this.disposables.push(vs.debug.onDidReceiveDebugSessionCustomEvent((e) => {
			if (e.event === "dart.testRunNotification") {
				this.handleNotification(e.body.suitePath, e.body.notification);
				this.disposables.push(vs.debug.onDidTerminateDebugSession((session) => {
					if (session.id === e.session.id)
						this.handleSessionEnd(suites[e.body.suitePath]);
				}));
			}
		}));
		this.disposables.push(vs.commands.registerCommand("dart.startDebuggingTest", (treeNode: SuiteTreeItem | TestTreeItem) => {
			vs.debug.startDebugging(
				vs.workspace.getWorkspaceFolder(treeNode.resourceUri),
				this.getLaunchConfig(false, treeNode),
			);
		}));
		this.disposables.push(vs.commands.registerCommand("dart.startWithoutDebuggingTest", (treeNode: SuiteTreeItem | TestTreeItem) => {
			vs.debug.startDebugging(
				vs.workspace.getWorkspaceFolder(treeNode.resourceUri),
				this.getLaunchConfig(true, treeNode),
			);
		}));

		this.disposables.push(vs.commands.registerCommand("_dart.displaySuite", (treeNode: SuiteTreeItem) => {
			return vs.commands.executeCommand("_dart.jumpToLineColInUri", vs.Uri.file(treeNode.suite.path));
		}));
		this.disposables.push(vs.commands.registerCommand("_dart.displayGroup", (treeNode: GroupTreeItem) => {
			return vs.commands.executeCommand(
				"_dart.jumpToLineColInUri",
				vs.Uri.parse(treeNode.group.url || treeNode.group.root_url),
				treeNode.group.root_line || treeNode.group.line,
				treeNode.group.root_column || treeNode.group.column,
			);
		}));
		this.disposables.push(vs.commands.registerCommand("_dart.displayTest", (treeNode: TestTreeItem) => {
			const output = getChannel("Test Output");
			output.clear();
			if (treeNode.outputEvents.length) {
				output.show(true);
				output.appendLine(`${treeNode.test.name}:\n`);
				for (let o of treeNode.outputEvents) {
					if (o.type === "error") {
						o = o as ErrorNotification;
						output.appendLine(`ERROR: ${o.error}`);
						output.appendLine(o.stackTrace);
					} else if (o.type === "print") {
						o = o as PrintNotification;
						output.appendLine(o.message);
					} else {
						output.appendLine(`Unknown message type '${o.type}'.`);
					}
				}
			}
			return vs.commands.executeCommand(
				"_dart.jumpToLineColInUri",
				vs.Uri.parse(treeNode.test.root_url || treeNode.test.url),
				treeNode.test.root_line || treeNode.test.line,
				treeNode.test.root_column || treeNode.test.column,
			);
		}));
	}

	private getLaunchConfig(noDebug: boolean, treeNode: SuiteTreeItem | TestTreeItem) {
		return {
			args: treeNode instanceof TestTreeItem ? ["--plain-name", treeNode.test.name] : undefined,
			name: "Tests",
			noDebug,
			program: fsPath(treeNode.resourceUri),
			request: "launch",
			type: "dart",
		};
	}

	public getTreeItem(element: vs.TreeItem): vs.TreeItem {
		return element;
	}

	public getChildren(element?: vs.TreeItem): vs.TreeItem[] {
		if (!element) {
			return _.flatMap(Object.keys(suites).map((k) => suites[k].suites));
		} else if (element instanceof SuiteTreeItem || element instanceof GroupTreeItem) {
			return element.children;
		}
	}

	public getParent?(element: vs.TreeItem): SuiteTreeItem | GroupTreeItem {
		if (element instanceof TestTreeItem || element instanceof GroupTreeItem)
			return element.parent;
	}

	private updateNode(node?: TestItemTreeItem): void {
		this.onDidChangeTreeDataEmitter.fire(node);
	}<commit_msg>Sort the suites in the tree alphabetically<commit_after>import * as _ from "lodash";
import * as path from "path";
import * as vs from "vscode";
import { getChannel } from "../commands/channels";
import { extensionPath } from "../extension";
import { fsPath } from "../utils";
import { DoneNotification, ErrorNotification, Group, GroupNotification, PrintNotification, Suite, SuiteNotification, Test, TestDoneNotification, TestStartNotification } from "./test_protocol";

const DART_TEST_SUITE_NODE = "dart-code:testSuiteNode";
const DART_TEST_GROUP_NODE = "dart-code:testGroupNode";
const DART_TEST_TEST_NODE = "dart-code:testTestNode";

const suites: { [key: string]: SuiteData } = {};

export class TestResultsProvider implements vs.Disposable, vs.TreeDataProvider<object> {
	private disposables: vs.Disposable[] = [];
	private onDidChangeTreeDataEmitter: vs.EventEmitter<vs.TreeItem | undefined> = new vs.EventEmitter<vs.TreeItem | undefined>();
	public readonly onDidChangeTreeData: vs.Event<vs.TreeItem | undefined> = this.onDidChangeTreeDataEmitter.event;
	private onDidStartTestsEmitter: vs.EventEmitter<vs.TreeItem | undefined> = new vs.EventEmitter<vs.TreeItem | undefined>();
	public readonly onDidStartTests: vs.Event<vs.TreeItem | undefined> = this.onDidStartTestsEmitter.event;

	// Set this flag we know when a new run starts so we can show the tree; however
	// we can't show it until we render a node (we can only call reveal on a node) so
	// we need to delay this until the suite starts.
	public static shouldShowTreeOnNextSuiteStart = true;

	constructor() {
		this.disposables.push(vs.debug.onDidReceiveDebugSessionCustomEvent((e) => {
			if (e.event === "dart.testRunNotification") {
				this.handleNotification(e.body.suitePath, e.body.notification);
				this.disposables.push(vs.debug.onDidTerminateDebugSession((session) => {
					if (session.id === e.session.id)
						this.handleSessionEnd(suites[e.body.suitePath]);
				}));
			}
		}));
		this.disposables.push(vs.commands.registerCommand("dart.startDebuggingTest", (treeNode: SuiteTreeItem | TestTreeItem) => {
			vs.debug.startDebugging(
				vs.workspace.getWorkspaceFolder(treeNode.resourceUri),
				this.getLaunchConfig(false, treeNode),
			);
		}));
		this.disposables.push(vs.commands.registerCommand("dart.startWithoutDebuggingTest", (treeNode: SuiteTreeItem | TestTreeItem) => {
			vs.debug.startDebugging(
				vs.workspace.getWorkspaceFolder(treeNode.resourceUri),
				this.getLaunchConfig(true, treeNode),
			);
		}));

		this.disposables.push(vs.commands.registerCommand("_dart.displaySuite", (treeNode: SuiteTreeItem) => {
			return vs.commands.executeCommand("_dart.jumpToLineColInUri", vs.Uri.file(treeNode.suite.path));
		}));
		this.disposables.push(vs.commands.registerCommand("_dart.displayGroup", (treeNode: GroupTreeItem) => {
			return vs.commands.executeCommand(
				"_dart.jumpToLineColInUri",
				vs.Uri.parse(treeNode.group.url || treeNode.group.root_url),
				treeNode.group.root_line || treeNode.group.line,
				treeNode.group.root_column || treeNode.group.column,
			);
		}));
		this.disposables.push(vs.commands.registerCommand("_dart.displayTest", (treeNode: TestTreeItem) => {
			const output = getChannel("Test Output");
			output.clear();
			if (treeNode.outputEvents.length) {
				output.show(true);
				output.appendLine(`${treeNode.test.name}:\n`);
				for (let o of treeNode.outputEvents) {
					if (o.type === "error") {
						o = o as ErrorNotification;
						output.appendLine(`ERROR: ${o.error}`);
						output.appendLine(o.stackTrace);
					} else if (o.type === "print") {
						o = o as PrintNotification;
						output.appendLine(o.message);
					} else {
						output.appendLine(`Unknown message type '${o.type}'.`);
					}
				}
			}
			return vs.commands.executeCommand(
				"_dart.jumpToLineColInUri",
				vs.Uri.parse(treeNode.test.root_url || treeNode.test.url),
				treeNode.test.root_line || treeNode.test.line,
				treeNode.test.root_column || treeNode.test.column,
			);
		}));
	}

	private getLaunchConfig(noDebug: boolean, treeNode: SuiteTreeItem | TestTreeItem) {
		return {
			args: treeNode instanceof TestTreeItem ? ["--plain-name", treeNode.test.name] : undefined,
			name: "Tests",
			noDebug,
			program: fsPath(treeNode.resourceUri),
			request: "launch",
			type: "dart",
		};
	}

	public getTreeItem(element: vs.TreeItem): vs.TreeItem {
		return element;
	}

	public getChildren(element?: vs.TreeItem): vs.TreeItem[] {
		let items = !element
			? _.flatMap(Object.keys(suites).map((k) => suites[k].suites))
			: (element instanceof SuiteTreeItem || element instanceof GroupTreeItem)
				? element.children
				: [];
		items = items.filter((item) => item);
		// Only sort suites, as tests may have a useful order themselves.
		if (!element)
			items = _.sortBy(items, (t) => t.label);
		return items;
	}

	public getParent?(element: vs.TreeItem): SuiteTreeItem | GroupTreeItem {
		if (element instanceof TestTreeItem || element instanceof GroupTreeItem)
			return element.parent;
	}

	private updateNode(node?: TestItemTreeItem): void {
		this.onDidChangeTreeDataEmitter.fire(node);
	}
{'fraction_non_alphanumeric': 0.1355223880597015, 'fraction_numerical': 0.0, 'mean_word_length': 4.559181415929204, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '200733', 'n_tokens_mistral': 3556, 'n_tokens_neox': 3168, 'n_words': 623}