{% extends "html/base.html" %}
{% block content %}
<section id="summary">
  <div class="container">
    <h1>Summary</h1>
    {% block summary %}
    <div class="metadata">
      <table>
        {% block session_metadata %}
        <tr>
          <th>Started</th>
          <td>{{ started|strftime(time_format) }}</td>
        </tr>
        <tr>
          <th>Ended</th>
          <td>
            {% if ended %}
            {{ ended|strftime(time_format) }}
            {% else %}
            <i>In progress...</i>
            {% endif %}
          </td>
        </tr>
        {% if ended %}
        <tr>
          <th>Duration</th>
          {% set duration = ended - started %}
          <td>{{ duration|timedelta }}</td>
        </tr>
        {% endif %}
        <tr>
          <th>Total run time</th>
          <td>{{ tests|map(attribute='phases')|map('sum', 'report.duration')|sum|timedelta }}</td>
        </tr>
        {% for key, value in metadata.items() %}
        <tr>
          <th>{{ key }}</th>
          <td>
            {% if value is mapping %}
            {% for key, value in value.items() %}
            {{ key }}: {{ value }}<br>
            {% endfor %}
            {% else %}
            {{ value|urlize }}
            {% endif %}
          </td>
        </tr>
        {% endfor %}
        {% endblock %}
        <tr id="tr_filter_string" style="display: none;">
          <th>Filter String</th>
          <td id="td_filter_string"></td>
        </tr>
      </table>
    </div>
    <div class="graph">
      {% set tests_by_category = tests|groupby('status.category') %}
      {% set nodes_run = tests|map(attribute='item.nodeid')|list %}
      {% set nof_nodes_not_run = session.items|rejectattr('nodeid', 'in', nodes_run)|list|count %}
      <svg width="200" height="200" viewBox="0 0 42 42">
        {% set ns = namespace(sum=0.0) %}
        {% set total = tests|count %}
        {% set r = 16 %}
        {% set spacing = 0.4 %}
        {% set C = 2 * 3.141592653589793 * r %}
        {% for category, sub_tests in tests_by_category %}
        {% set count = sub_tests|count %}
        {% set L = count / (total + nof_nodes_not_run) * C %}
        {% set color = colors[category] %}
        <circle
                class="donut-segment {{ category }}"
                stroke-dasharray="{{ [L - spacing, 0]|max }} {{ C - (L - spacing) }}"
                stroke-dashoffset="{{ C - ns.sum + C / 4 - spacing / 2 }}"
                cx="21"
                cy="21"
                r="{{ r }}"
                fill="transparent"
                {% if color %}
                stroke="{{ color[0] }}"
                {% endif %}
                stroke-width="4">
        </circle>
        {% set ns.sum = ns.sum + L %}
        {% endfor %}
        <text x="21" y="24" text-anchor="middle">{{ total }}</text>
      </svg>
      <div class="legend">
        {% for category, tests in tests_by_category %}
        <span class="status badge {{ category }} {{ tests|map(attribute='status.style')|first|join(' ') }}">
            {{ tests|count }}
          </span>
        <span>{{ category }}</span>
        {% endfor %}
        {% if nof_nodes_not_run %}
        <span class="status badge notrun">{{ nof_nodes_not_run }}</span>
        <span>not run</span>
        {% endif %}
      </div>
    </div>
    {% endblock %}
  </div>
</section>
{% block coverage %}
{% endblock %}
{% if warnings %}
<section id="warnings">
  <div class="container">
    <h1>Warnings</h1>
    {% for warning in warnings %}
    <div class="status badge warning">WARNING</div>
    <div>{{ warning.filename }}:{{ warning.lineno }}<br>{{ warning.message }}</div>
    {% endfor %}
  </div>
</section>
{% endif %}
<section id="test-files">
  <div class="container">
    <!--函数总长度-->
    {% set c = namespace(counter = 0) %}
    {% set test_items = [] %}
    {% for test in tests %}
    {% if test.status.category != 'skipped' %}
    {% set c.counter = c.counter + 1 %}
    {% set name = test.item.nodeid.split('::')[1:]|join('::') %}
    {% if test.item.nodeid not in test_items %}
    {{ test_items.append(test.item.nodeid) or "" }}
    {% endif %}
    {% endif %}
    {% endfor %}

    <!--覆盖point的函数个数-->
    {% set uf = namespace(unique_functions = {}) %}
    {% for group in coverages.functional.groups %}
    {% for point in group.points %}
    {% for func_list in point.functions.values() %}
    {% for func in func_list %}
    {% set processed_func = func %}
    {% if '::' in func %}
    {% if ':' in func %}
    {% set before_colon = func.split(':', 1)[0] %}
    {% else %}
    {% set before_colon = func.split('::', 1)[0] %}
    {% endif %}
    {% set after_double_colon = func.split('::', 1)[1] %}
    {% set processed_func = before_colon ~ '::' ~ after_double_colon %}
    {% elif '.' in func and '.py' not in func %}
    {% set parts = func.split('.') %}
    {% if parts|length >= 2 %}
    {% set path_part = parts[:-1]|join('/') ~ '.py' %}
    {% set func_part = parts[-1] %}
    {% set processed_func = path_part ~ '::' ~ func_part %}
    {% else %}
    {% set processed_func = func %}
    {% endif %}
    {% else %}
    {% set processed_func = func %}
    {% endif %}
    {% if processed_func not in uf.unique_functions %}
    {% for item in test_items %}
    {% if item in processed_func %}
    {% set _ = uf.unique_functions.update({processed_func: true}) %}
    {% endif %}
    {% endfor %}
    {% endif %}
    {% endfor %}
    {% endfor %}
    {% endfor %}
    {% endfor %}
    <div style="margin-bottom: 1rem; margin-left: 0.5rem">
      <span class="fspath" style="font-weight: bold">Marked Functions: </span>
      <span style="font-weight: bold;
        {% if c.counter != 0 and (uf.unique_functions.keys()|length / c.counter * 100) < 100 %}
          color: red;
        {% endif %}">
        {{ uf.unique_functions.keys()|length }}/{{ c.counter }}
        {% if c.counter != 0 %}
          ({{ (uf.unique_functions.keys()|length / c.counter * 100)|round(2) }}%)
        {% endif %}
      </span>
    </div>
    <!--每个文件对应几个point-->
    {% set path_to_point_names = {} %}
    {% set func_to_point_names = {} %}
    {% for group in coverages.functional.groups %}
    {% for point in group.points %}
    {% for bin_name, func_list in point.functions.items() %}
    {% for func in func_list %}
    {# 处理两种格式的函数路径 #}
    {% if '::' in func %}
    {# 格式1: 文件路径格式 /path/to/file.py::function_name #}
    {% set parts = func.split('::') %}
    {% set path = parts[0].split(':')[0] %}
    {% set func_name = parts[-1] %}
    {% else %}
    {# 格式2: 模块路径格式 module.submodule.function_name #}
    {% set parts = func.split('.') %}
    {% if parts|length >= 3 %}
    {% set path = parts[0:-1]|join('/') + '.py' %}
    {% set func_name = parts[-1] %}
    {% endif %}
    {% endif %}

    {% if path and func_name %}
    {% set su = namespace(should_update=false) %}
    {% for item in test_items %}
    {% if item in path + '::' + func_name %}
    {% set su.should_update = true %}
    {% endif %}
    {% endfor %}

    {% if su.should_update %}
    {# 更新 path_to_point_names #}
    {% if not path_to_point_names.get(path) %}
    {% set path_to_point_names = path_to_point_names.update({path: [group.name + ':' + point.name]}) %}
    {% else %}
    {% if group.name + ':' + point.name not in path_to_point_names[path] %}
    {% set path_to_point_names = path_to_point_names.update({
    path: path_to_point_names[path] + [group.name + ':' + point.name]
    }) %}
    {% endif %}
    {% endif %}
    {% endif %}

    {# 更新 func_to_point_names #}
    {% set func_key = path + ':' + func_name %}
    {% if not func_to_point_names.get(func_key) %}
    {% set func_to_point_names = func_to_point_names.update({func_key: [group.name + ':' + point.name]}) %}
    {% else %}
    {% if group.name + ':' + point.name not in func_to_point_names[func_key] %}
    {% set func_to_point_names = func_to_point_names.update({
    func_key: func_to_point_names[func_key] + [group.name + ':' + point.name]
    }) %}
    {% endif %}
    {% endif %}
    {% endif %}
    {% endfor %}
    {% endfor %}
    {% endfor %}
    {% endfor %}

    {% for fspath, tests in tests|groupby('item.fspath') %}
    {% set first_item = tests|map(attribute='item')|first %}
    <details class="file">
      <summary>
        <h2 class="title file-title">
          {% block module_title scoped %}
          <span class="fspath">
              {% block module_name scoped %}
              {{ first_item.nodeid.split('::')|first }}
              {% endblock %}
            </span>
          <span class="counts">
            {% for category, tests in tests|groupby('status.category') -%}
              <span title="{{ tests|count }} {{ category }}" class="count status badge {{ category }} {{ tests|map(attribute='status.style')|first|join(' ') }}">{{ tests|count }}</span>
            {%- endfor %}
            </span>
          {% set pc = namespace(point_count = 0) %}
          {% for path,point_names in path_to_point_names.items() %}
          {% if first_item.nodeid.split('::')|first in path %}
          {% set pc.point_count = point_names|length %}
          {% endif %}
          {% endfor %}
          <span>
          <span class="point-num {% if pc.point_count > 0 %}point-num-green{% else %}point-num-red{% endif %}" style="margin-left: 1rem;">{{pc.point_count}}</span>
          </span>
          <div class="duration">
            {{ tests|map(attribute='phases')|map('sum', 'report.duration')|sum|timedelta }}
          </div>
          {% endblock %}
        </h2>
      </summary>
      <div class="content box">
        {% include "html/module.html" %}
      </div>
    </details>
    {% endfor %}
  </div>
</section>
{% endblock %}