<commit_before>#!/usr/bin/env python3
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

import base64
import json
from textwrap import indent
from typing import Any, Dict, List, Optional
from uuid import uuid4

from idb.common.types import (
    AppProcessState,
    CompanionInfo,
    InstalledAppInfo,
    InstalledTestInfo,
    TargetDescription,
    TestActivity,
    TestRunInfo,
)
from treelib import Tree


def human_format_test_info(test: TestRunInfo) -> str:
    output = ""

    info_list = [
        f"{test.bundle_name} - {test.class_name}/{test.method_name}",
        f"Passed: {test.passed}",
        f"Crashed: {test.crashed}",
        f"Duration: {test.duration}",
    ]
    failure_info = test.failure_info
    if failure_info:
        info_list += [
            f"Failure message: {failure_info.message}",
            f"Location {failure_info.file}:{failure_info.line}",
        ]
    output += " | ".join(info_list)

    if len(test.logs) > 0:
        log_lines = indent("\n".join(test.logs), " " * 4)
        output += "\n" + indent("Logs:\n" + log_lines, " " * 4)

    if test.activityLogs:
        output += f"\n{human_format_activities(test.activityLogs)}"
    return output


def human_format_activities(activities: List[TestActivity]) -> str:
    tree: Tree = Tree()
    start = activities[0].start

    def process_activity(activity: TestActivity, parent: Optional[str] = None) -> None:
        tree.create_node(
            f"{activity.name} ({activity.finish - start:.2f}s)",
            activity.uuid,
            parent=parent,
        )
        for attachment in activity.attachments:
            tree.create_node(
                f"Attachment: {attachment.name}", uuid4(), parent=activity.uuid
            )
        for sub_activity in activity.sub_activities:
            process_activity(sub_activity, parent=activity.uuid)

    tree.create_node("Activities", "activities")
    for activity in activities:
        process_activity(activity, "activities")

    return str(tree)


def json_format_test_info(test: TestRunInfo) -> str:
    failure_info = test.failure_info
    data = {
        "bundleName": test.bundle_name,
        "className": test.class_name,
        "methodName": test.method_name,
        "logs": test.logs,
        "duration": test.duration,
        "passed": test.passed,
        "crashed": test.crashed,
        "failureInfo": {
            "message": failure_info.message,
            "file": failure_info.file,
            "line": failure_info.line,
        }<commit_msg>Sort treelib output by start time<commit_after>#!/usr/bin/env python3
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

import base64
import json
from textwrap import indent
from typing import Any, Dict, List, Optional
from uuid import uuid4

from idb.common.types import (
    AppProcessState,
    CompanionInfo,
    InstalledAppInfo,
    InstalledTestInfo,
    TargetDescription,
    TestActivity,
    TestRunInfo,
)
from treelib import Tree


def human_format_test_info(test: TestRunInfo) -> str:
    output = ""

    info_list = [
        f"{test.bundle_name} - {test.class_name}/{test.method_name}",
        f"Passed: {test.passed}",
        f"Crashed: {test.crashed}",
        f"Duration: {test.duration}",
    ]
    failure_info = test.failure_info
    if failure_info:
        info_list += [
            f"Failure message: {failure_info.message}",
            f"Location {failure_info.file}:{failure_info.line}",
        ]
    output += " | ".join(info_list)

    if len(test.logs) > 0:
        log_lines = indent("\n".join(test.logs), " " * 4)
        output += "\n" + indent("Logs:\n" + log_lines, " " * 4)

    if test.activityLogs:
        output += f"\n{human_format_activities(test.activityLogs)}"
    return output


def human_format_activities(activities: List[TestActivity]) -> str:
    tree: Tree = Tree()
    start = activities[0].start

    def process_activity(activity: TestActivity, parent: Optional[str] = None) -> None:
        tree.create_node(
            f"{activity.name} ({activity.finish - start:.2f}s)",
            activity.uuid,
            parent=parent,
            data={"start": activity.start},
        )
        for attachment in activity.attachments:
            tree.create_node(
                f"Attachment: {attachment.name}",
                uuid4(),
                parent=activity.uuid,
                data={"start": activity.start},
            )
        for sub_activity in activity.sub_activities:
            process_activity(sub_activity, parent=activity.uuid)

    tree.create_node("Activities", "activities", data={"start": 0})
    for activity in activities:
        process_activity(activity, "activities")

    return tree.show(key=lambda n: n.data["start"], stdout=False)


def json_format_test_info(test: TestRunInfo) -> str:
    failure_info = test.failure_info
    data = {
        "bundleName": test.bundle_name,
        "className": test.class_name,
        "methodName": test.method_name,
        "logs": test.logs,
        "duration": test.duration,
        "passed": test.passed,
        "crashed": test.crashed,
        "failureInfo": {
            "message": failure_info.message,
            "file": failure_info.file,
            "line": failure_info.line,
        }
{'fraction_non_alphanumeric': 0.11913814955640051, 'fraction_numerical': 0.0038022813688212928, 'mean_word_length': 2.598697068403909, 'pattern_counts': {'":': 25, '<': 3, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '311599', 'n_tokens_mistral': 1676, 'n_tokens_neox': 1645, 'n_words': 378}