Kea2-python 0.3.2__py3-none-any.whl → 0.3.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of Kea2-python might be problematic. Click here for more details.

kea2/assets/quicktest.py CHANGED
@@ -52,7 +52,7 @@ class Omni_Notes_Sample(unittest.TestCase):
52
52
  assert self.d(resourceId="it.feio.android.omninotes.alpha:id/search_src_text").exists()
53
53
 
54
54
 
55
- URL = "https://raw.githubusercontent.com/ecnusse/Kea2/refs/heads/dev_test_hidden_algorithm/omninotes.apk"
55
+ URL = "https://github.com/federicoiosue/Omni-Notes/releases/download/6.2.0_alpha/OmniNotes-alphaRelease-6.2.0.apk"
56
56
  PACKAGE_NAME = "it.feio.android.omninotes.alpha"
57
57
  FILE_NAME = "omninotes.apk"
58
58
 
@@ -388,6 +388,10 @@ class BugReportGenerator:
388
388
  data["all_properties_count"] = len(self.test_result)
389
389
  data["executed_properties_count"] = sum(1 for result in self.test_result.values() if result.get("executed", 0) > 0)
390
390
 
391
+ # Calculate detailed property statistics for table headers
392
+ property_stats_summary = self._calculate_property_stats_summary(self.test_result)
393
+ data["property_stats_summary"] = property_stats_summary
394
+
391
395
  # Process coverage data
392
396
  data["coverage_trend"] = self.cov_trend
393
397
 
@@ -567,7 +571,8 @@ class BugReportGenerator:
567
571
  'property_execution_data': json.dumps(data["property_execution_trend"]),
568
572
  'activity_count_history': data["activity_count_history"],
569
573
  'crash_events': data["crash_events"],
570
- 'anr_events': data["anr_events"]
574
+ 'anr_events': data["anr_events"],
575
+ 'property_stats_summary': data["property_stats_summary"]
571
576
  }
572
577
 
573
578
  # Check if template exists, if not create it
@@ -822,6 +827,38 @@ class BugReportGenerator:
822
827
 
823
828
  return property_execution_trend
824
829
 
830
+ def _calculate_property_stats_summary(self, test_result: TestResult) -> Dict[str, int]:
831
+ """
832
+ Calculate summary statistics for property checking table headers
833
+
834
+ Args:
835
+ test_result: Test result data containing property statistics
836
+
837
+ Returns:
838
+ Dict: Summary statistics for each column
839
+ """
840
+ stats_summary = {
841
+ "total_properties": 0,
842
+ "total_precond_satisfied": 0,
843
+ "total_executed": 0,
844
+ "total_fails": 0,
845
+ "total_errors": 0,
846
+ "properties_with_errors": 0
847
+ }
848
+
849
+ for property_name, result in test_result.items():
850
+ stats_summary["total_properties"] += 1
851
+ stats_summary["total_precond_satisfied"] += result.get("precond_satisfied", 0)
852
+ stats_summary["total_executed"] += result.get("executed", 0)
853
+ stats_summary["total_fails"] += result.get("fail", 0)
854
+ stats_summary["total_errors"] += result.get("error", 0)
855
+
856
+ # Count properties that have errors or fails
857
+ if result.get("fail", 0) > 0 or result.get("error", 0) > 0:
858
+ stats_summary["properties_with_errors"] += 1
859
+
860
+ return stats_summary
861
+
825
862
  def _load_crash_dump_data(self) -> Tuple[List[Dict], List[Dict]]:
826
863
  """
827
864
  Load crash and ANR events from crash-dump.log file
kea2/keaUtils.py CHANGED
@@ -198,6 +198,9 @@ class PropStatistic:
198
198
  executed: int = 0
199
199
  fail: int = 0
200
200
  error: int = 0
201
+
202
+
203
+ PBTTestResult = NewType("PBTTestResult", Dict[PropName, PropStatistic])
201
204
 
202
205
 
203
206
  PropertyExecutionInfoStore = NewType("PropertyExecutionInfoStore", Deque["PropertyExecutionInfo"])
@@ -209,11 +212,6 @@ class PropertyExecutionInfo:
209
212
  tb: str
210
213
 
211
214
 
212
- class PBTTestResult(dict):
213
- def __getitem__(self, key) -> PropStatistic:
214
- return super().__getitem__(key)
215
-
216
-
217
215
  def getFullPropName(testCase: TestCase):
218
216
  return ".".join([
219
217
  testCase.__module__,
@@ -277,10 +275,15 @@ class JsonResult(TextTestResult):
277
275
  self.lastExecutedInfo.state = "pass"
278
276
 
279
277
  self.executionInfoStore.append(self.lastExecutedInfo)
280
-
281
278
 
282
279
  def getExcuted(self, test: TestCase):
283
280
  return self.res[getFullPropName(test)].executed
281
+
282
+ def logSummary(self):
283
+ fails = sum(_.fail for _ in self.res.values())
284
+ errors = sum(_.error for _ in self.res.values())
285
+
286
+ logger.info(f"[Property Exectution Summary] Errors:{errors}, Fails:{fails}")
284
287
 
285
288
 
286
289
  class KeaTestRunner(TextTestRunner):
@@ -465,6 +468,8 @@ class KeaTestRunner(TextTestRunner):
465
468
  else:
466
469
  self.stream.write("\n")
467
470
  self.stream.flush()
471
+
472
+ result.logSummary()
468
473
  return result
469
474
 
470
475
  @property
@@ -211,35 +211,39 @@
211
211
  text-align: left !important;
212
212
  }
213
213
 
214
- /* Enhanced Error Details styling */
215
- .table-custom td:nth-child(7) .collapse {
214
+ /* Enhanced Error Details styling for Property Statistics */
215
+ .table-custom tr.collapse {
216
216
  position: relative;
217
217
  z-index: 10;
218
218
  }
219
219
 
220
- .table-custom td:nth-child(7) .card {
221
- max-width: none;
222
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
220
+ .table-custom tr.collapse td {
221
+ border-top: none;
222
+ padding-top: 0;
223
223
  }
224
224
 
225
- .table-custom td:nth-child(7) .card-body {
226
- padding: 1rem;
227
- max-height: 400px;
228
- overflow-y: auto;
225
+ .table-custom tr.collapse .bg-light {
226
+ max-width: none;
227
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
228
+ border: 1px solid #e9ecef;
229
229
  }
230
230
 
231
- .table-custom td:nth-child(7) pre {
232
- max-height: 200px;
231
+ .table-custom tr.collapse pre {
232
+ max-height: 300px;
233
233
  overflow-y: auto;
234
- font-size: 0.8rem;
234
+ font-size: 0.85rem;
235
235
  line-height: 1.4;
236
+ background-color: #f8f9fa;
237
+ border: 1px solid #e9ecef;
238
+ border-radius: 4px;
239
+ padding: 0.75rem;
236
240
  }
237
241
 
238
- .table-custom td:nth-child(7) details {
242
+ .table-custom tr.collapse details {
239
243
  margin-top: 0.5rem;
240
244
  }
241
245
 
242
- .table-custom td:nth-child(7) summary {
246
+ .table-custom tr.collapse summary {
243
247
  cursor: pointer;
244
248
  margin-bottom: 0.5rem;
245
249
  }
@@ -1270,7 +1274,7 @@
1270
1274
  <table class="table table-custom table-activities">
1271
1275
  <thead>
1272
1276
  <tr>
1273
- <th>Activity Name</th>
1277
+ <th>Activity Name <span class="badge bg-primary ms-2" style="font-size: 0.9rem; font-weight: 600;">{{ tested_activities_count }}/{{ total_activities_count }}</span></th>
1274
1278
  <th>Visit Count <i class="bi bi-arrow-down-up text-muted sort-icon activities-sort-icon" id="visit-count-sort" data-column="visit-count" data-order="none" style="cursor: pointer;"></i></th>
1275
1279
  </tr>
1276
1280
  </thead>
@@ -1576,11 +1580,11 @@
1576
1580
  <thead>
1577
1581
  <tr>
1578
1582
  <th>Index</th>
1579
- <th>Property Name</th>
1580
- <th>Precondition Satisfied</th>
1581
- <th>Executed</th>
1582
- <th>Fails <i class="bi bi-arrow-down-up text-muted sort-icon" id="fails-sort" data-column="fails" data-order="none" style="cursor: pointer;"></i></th>
1583
- <th>Errors <i class="bi bi-arrow-down-up text-muted sort-icon" id="errors-sort" data-column="errors" data-order="none" style="cursor: pointer;"></i></th>
1583
+ <th>Property Name <span class="badge bg-primary ms-2" style="font-size: 0.9rem; font-weight: 600;">{{ property_stats_summary.total_properties }}</span></th>
1584
+ <th>Precondition Satisfied <span class="badge bg-success ms-2" style="font-size: 0.9rem; font-weight: 600;">{{ property_stats_summary.total_precond_satisfied }}</span></th>
1585
+ <th>Executed <span class="badge bg-info ms-2" style="font-size: 0.9rem; font-weight: 600;">{{ property_stats_summary.total_executed }}</span></th>
1586
+ <th>Fails <span class="badge bg-danger ms-2" style="font-size: 0.9rem; font-weight: 600;">{{ property_stats_summary.total_fails }}</span> <i class="bi bi-arrow-down-up text-muted sort-icon" id="fails-sort" data-column="fails" data-order="none" style="cursor: pointer;"></i></th>
1587
+ <th>Errors <span class="badge bg-warning ms-2" style="font-size: 0.9rem; font-weight: 600;">{{ property_stats_summary.total_errors }}</span> <i class="bi bi-arrow-down-up text-muted sort-icon" id="errors-sort" data-column="errors" data-order="none" style="cursor: pointer;"></i></th>
1584
1588
  <th>Error Details</th>
1585
1589
  </tr>
1586
1590
  </thead>
@@ -1605,127 +1609,140 @@
1605
1609
  {% set property_index = loop.index %}
1606
1610
  {% if error_list|length == 1 %}
1607
1611
  <!-- Single error - simple display -->
1608
- <button class="btn btn-sm btn-outline-danger" type="button" data-bs-toggle="collapse"
1609
- data-bs-target="#single-error-detail-{{ property_index }}" aria-expanded="false"
1612
+ <button class="btn btn-sm btn-outline-danger" type="button" data-bs-toggle="collapse"
1613
+ data-bs-target="#single-error-detail-{{ property_index }}" aria-expanded="false"
1610
1614
  aria-controls="single-error-detail-{{ property_index }}">
1611
1615
  <i class="bi bi-exclamation-triangle"></i> View Error
1612
1616
  </button>
1613
- <div class="collapse mt-2" id="single-error-detail-{{ property_index }}">
1614
- <div class="card card-body bg-light">
1615
- <div class="mb-2">
1616
- <span class="badge bg-{{ 'danger' if error_list[0].state == 'fail' else 'warning' }}">
1617
- {{ error_list[0].state|upper }}
1618
- </span>
1619
- {% if error_list[0].occurrence_count > 1 %}
1620
- <span class="badge bg-info ms-2">
1621
- Occurred {{ error_list[0].occurrence_count }} times
1622
- </span>
1623
- {% endif %}
1624
- {% if error_list[0].startStepsCountList is defined and error_list[0].startStepsCountList|length > 0 %}
1625
- <span class="badge bg-secondary ms-2">
1626
- <i class="bi bi-step-forward"></i> Monkey Steps: {{ error_list[0].startStepsCountList|join(', ') }}
1627
- </span>
1628
- {% endif %}
1629
- </div>
1630
- {% if error_list[0].short_description %}
1631
- <div class="mb-2">
1632
- <strong>Error:</strong> <code>{{ error_list[0].short_description }}</code>
1633
- </div>
1634
- {% endif %}
1635
- <details>
1636
- <summary class="btn btn-sm btn-outline-secondary mb-2">Show Full Traceback</summary>
1637
- <pre class="text-danger mb-0" style="font-size: 0.85rem; white-space: pre-wrap;">{{ error_list[0].traceback }}</pre>
1638
- </details>
1639
- </div>
1640
- </div>
1641
1617
  {% else %}
1642
1618
  <!-- Multiple errors - tabbed display -->
1643
- <button class="btn btn-sm btn-outline-danger" type="button" data-bs-toggle="collapse"
1644
- data-bs-target="#multi-error-detail-{{ property_index }}" aria-expanded="false"
1619
+ <button class="btn btn-sm btn-outline-danger" type="button" data-bs-toggle="collapse"
1620
+ data-bs-target="#multi-error-detail-{{ property_index }}" aria-expanded="false"
1645
1621
  aria-controls="multi-error-detail-{{ property_index }}">
1646
1622
  <i class="bi bi-exclamation-triangle"></i> View {{ error_list|length }} Errors
1647
1623
  </button>
1648
- <div class="collapse mt-2" id="multi-error-detail-{{ property_index }}">
1649
- <div class="card card-body bg-light">
1650
- <!-- Error summary -->
1651
- <div class="mb-3">
1652
- <h6 class="text-danger">Multiple Errors Detected</h6>
1653
- <div class="d-flex flex-wrap gap-1">
1654
- {% for error in error_list %}
1655
- <span class="badge bg-{{ 'danger' if error.state == 'fail' else 'warning' }}">
1656
- {{ error.state|upper }} #{{ loop.index }}
1657
- {% if error.occurrence_count > 1 %} ({{ error.occurrence_count }}x){% endif %}
1658
- {% if error.startStepsCountList is defined and error.startStepsCountList|length > 0 %}
1659
- @{% if error.startStepsCountList|length == 1 %}{{ error.startStepsCountList[0] }}{% else %}{{ error.startStepsCountList[0] }}-{{ error.startStepsCountList[-1] }}{% endif %}
1660
- {% endif %}
1661
- </span>
1662
- {% endfor %}
1663
- </div>
1624
+ {% endif %}
1625
+ {% else %}
1626
+ <span class="text-muted">-</span>
1627
+ {% endif %}
1628
+ </td>
1629
+ </tr>
1630
+ {% if (test_result.fail|default(0) > 0 or test_result.error|default(0) > 0) and property_name in property_error_details %}
1631
+ {% set error_list = property_error_details[property_name] %}
1632
+ {% set property_index = loop.index %}
1633
+ {% if error_list|length == 1 %}
1634
+ <!-- Single error detail row -->
1635
+ <tr class="collapse" id="single-error-detail-{{ property_index }}">
1636
+ <td colspan="7">
1637
+ <div class="bg-light p-3 rounded">
1638
+ <div class="mb-2">
1639
+ <span class="badge bg-{{ 'danger' if error_list[0].state == 'fail' else 'warning' }}">
1640
+ {{ error_list[0].state|upper }}
1641
+ </span>
1642
+ {% if error_list[0].occurrence_count > 1 %}
1643
+ <span class="badge bg-info ms-2">
1644
+ Occurred {{ error_list[0].occurrence_count }} times
1645
+ </span>
1646
+ {% endif %}
1647
+ {% if error_list[0].startStepsCountList is defined and error_list[0].startStepsCountList|length > 0 %}
1648
+ <span class="badge bg-secondary ms-2">
1649
+ <i class="bi bi-step-forward"></i> Monkey Steps: {{ error_list[0].startStepsCountList|join(', ') }}
1650
+ </span>
1651
+ {% endif %}
1652
+ </div>
1653
+ {% if error_list[0].short_description %}
1654
+ <div class="mb-2">
1655
+ <strong>Error:</strong> <code>{{ error_list[0].short_description }}</code>
1664
1656
  </div>
1665
-
1666
- <!-- Error tabs -->
1667
- <ul class="nav nav-pills nav-fill mb-3" id="multi-error-tabs-{{ property_index }}" role="tablist">
1668
- {% for error in error_list %}
1669
- <li class="nav-item" role="presentation">
1670
- <button class="nav-link {{ 'active' if loop.first else '' }} btn-sm"
1671
- id="multi-error-tab-{{ property_index }}-{{ loop.index }}"
1672
- data-bs-toggle="pill"
1673
- data-bs-target="#multi-error-content-{{ property_index }}-{{ loop.index }}"
1674
- type="button" role="tab"
1675
- aria-controls="multi-error-content-{{ property_index }}-{{ loop.index }}"
1676
- aria-selected="{{ 'true' if loop.first else 'false' }}">
1677
- <span class="badge bg-{{ 'danger' if error.state == 'fail' else 'warning' }} me-1">
1678
- {{ error.state|upper }}
1679
- </span>
1680
- #{{ loop.index }}
1681
- </button>
1682
- </li>
1683
- {% endfor %}
1684
- </ul>
1685
-
1686
- <!-- Error content -->
1687
- <div class="tab-content" id="multi-error-content-{{ property_index }}">
1657
+ {% endif %}
1658
+ <details>
1659
+ <summary class="btn btn-sm btn-outline-secondary mb-2">Show Full Traceback</summary>
1660
+ <pre class="text-danger mb-0 text-start" style="font-size: 0.85rem; white-space: pre-wrap; text-align: left;">{{ error_list[0].traceback }}</pre>
1661
+ </details>
1662
+ </div>
1663
+ </td>
1664
+ </tr>
1665
+ {% else %}
1666
+ <!-- Multiple errors detail row -->
1667
+ <tr class="collapse" id="multi-error-detail-{{ property_index }}">
1668
+ <td colspan="7">
1669
+ <div class="bg-light p-3 rounded">
1670
+ <!-- Error summary -->
1671
+ <div class="mb-3">
1672
+ <h6 class="text-danger">Multiple Errors Detected</h6>
1673
+ <div class="d-flex flex-wrap gap-1">
1688
1674
  {% for error in error_list %}
1689
- <div class="tab-pane fade {{ 'show active' if loop.first else '' }}"
1690
- id="multi-error-content-{{ property_index }}-{{ loop.index }}"
1691
- role="tabpanel"
1692
- aria-labelledby="multi-error-tab-{{ property_index }}-{{ loop.index }}">
1693
- <div class="mb-2">
1694
- <span class="badge bg-{{ 'danger' if error.state == 'fail' else 'warning' }}">
1695
- {{ error.state|upper }} #{{ loop.index }}
1696
- </span>
1697
- <small class="text-muted ms-2">Error {{ loop.index }} of {{ loop.length }}</small>
1698
- {% if error.occurrence_count > 1 %}
1699
- <span class="badge bg-info ms-2">
1700
- {{ error.occurrence_count }} occurrences
1701
- </span>
1702
- {% endif %}
1675
+ <span class="badge bg-{{ 'danger' if error.state == 'fail' else 'warning' }}">
1676
+ {{ error.state|upper }} #{{ loop.index }}
1677
+ {% if error.occurrence_count > 1 %} ({{ error.occurrence_count }}x){% endif %}
1703
1678
  {% if error.startStepsCountList is defined and error.startStepsCountList|length > 0 %}
1704
- <span class="badge bg-secondary ms-2">
1705
- <i class="bi bi-step-forward"></i> Monkey Steps: {{ error.startStepsCountList|join(', ') }}
1706
- </span>
1679
+ @{% if error.startStepsCountList|length == 1 %}{{ error.startStepsCountList[0] }}{% else %}{{ error.startStepsCountList[0] }}-{{ error.startStepsCountList[-1] }}{% endif %}
1707
1680
  {% endif %}
1708
- </div>
1709
- {% if error.short_description %}
1710
- <div class="mb-2">
1711
- <strong>Error:</strong> <code>{{ error.short_description }}</code>
1712
- </div>
1681
+ </span>
1682
+ {% endfor %}
1683
+ </div>
1684
+ </div>
1685
+
1686
+ <!-- Error tabs -->
1687
+ <ul class="nav nav-pills nav-fill mb-3" id="multi-error-tabs-{{ property_index }}" role="tablist">
1688
+ {% for error in error_list %}
1689
+ <li class="nav-item" role="presentation">
1690
+ <button class="nav-link {{ 'active' if loop.first else '' }} btn-sm"
1691
+ id="multi-error-tab-{{ property_index }}-{{ loop.index }}"
1692
+ data-bs-toggle="pill"
1693
+ data-bs-target="#multi-error-content-{{ property_index }}-{{ loop.index }}"
1694
+ type="button" role="tab"
1695
+ aria-controls="multi-error-content-{{ property_index }}-{{ loop.index }}"
1696
+ aria-selected="{{ 'true' if loop.first else 'false' }}">
1697
+ <span class="badge bg-{{ 'danger' if error.state == 'fail' else 'warning' }} me-1">
1698
+ {{ error.state|upper }}
1699
+ </span>
1700
+ #{{ loop.index }}
1701
+ </button>
1702
+ </li>
1703
+ {% endfor %}
1704
+ </ul>
1705
+
1706
+ <!-- Error content -->
1707
+ <div class="tab-content" id="multi-error-content-{{ property_index }}">
1708
+ {% for error in error_list %}
1709
+ <div class="tab-pane fade {{ 'show active' if loop.first else '' }}"
1710
+ id="multi-error-content-{{ property_index }}-{{ loop.index }}"
1711
+ role="tabpanel"
1712
+ aria-labelledby="multi-error-tab-{{ property_index }}-{{ loop.index }}">
1713
+ <div class="mb-2">
1714
+ <span class="badge bg-{{ 'danger' if error.state == 'fail' else 'warning' }}">
1715
+ {{ error.state|upper }} #{{ loop.index }}
1716
+ </span>
1717
+ <small class="text-muted ms-2">Error {{ loop.index }} of {{ loop.length }}</small>
1718
+ {% if error.occurrence_count > 1 %}
1719
+ <span class="badge bg-info ms-2">
1720
+ {{ error.occurrence_count }} occurrences
1721
+ </span>
1722
+ {% endif %}
1723
+ {% if error.startStepsCountList is defined and error.startStepsCountList|length > 0 %}
1724
+ <span class="badge bg-secondary ms-2">
1725
+ <i class="bi bi-step-forward"></i> Monkey Steps: {{ error.startStepsCountList|join(', ') }}
1726
+ </span>
1713
1727
  {% endif %}
1714
- <details>
1715
- <summary class="btn btn-sm btn-outline-secondary mb-2">Show Full Traceback</summary>
1716
- <pre class="text-danger mb-0" style="font-size: 0.85rem; white-space: pre-wrap;">{{ error.traceback }}</pre>
1717
- </details>
1718
1728
  </div>
1719
- {% endfor %}
1729
+ {% if error.short_description %}
1730
+ <div class="mb-2">
1731
+ <strong>Error:</strong> <code>{{ error.short_description }}</code>
1732
+ </div>
1733
+ {% endif %}
1734
+ <details>
1735
+ <summary class="btn btn-sm btn-outline-secondary mb-2">Show Full Traceback</summary>
1736
+ <pre class="text-danger mb-0 text-start" style="font-size: 0.85rem; white-space: pre-wrap; text-align: left;">{{ error.traceback }}</pre>
1737
+ </details>
1720
1738
  </div>
1739
+ {% endfor %}
1721
1740
  </div>
1722
1741
  </div>
1723
- {% endif %}
1724
- {% else %}
1725
- <span class="text-muted">-</span>
1726
- {% endif %}
1727
- </td>
1728
- </tr>
1742
+ </td>
1743
+ </tr>
1744
+ {% endif %}
1745
+ {% endif %}
1729
1746
  {% endfor %}
1730
1747
  </tbody>
1731
1748
  </table>
@@ -1208,9 +1208,55 @@
1208
1208
  <div class="summary-card">
1209
1209
  <h2 class="section-title">Test Summary</h2>
1210
1210
 
1211
+ <!-- Statistics Cards -->
1212
+ <div class="row g-4">
1213
+ <div class="col-lg-2 col-md-4 col-sm-6">
1214
+ <div class="text-center">
1215
+ <i class="bi bi-bug text-danger" style="font-size: 2rem;"></i>
1216
+ <span class="stat-value value-danger">{{ bugs_found }}</span>
1217
+ <span class="stat-label">Bugs Found</span>
1218
+ </div>
1219
+ </div>
1220
+ <div class="col-lg-2 col-md-4 col-sm-6">
1221
+ <div class="text-center">
1222
+ <i class="bi bi-x-circle text-danger" style="font-size: 2rem;"></i>
1223
+ <span class="stat-value value-danger">{{ total_crash_count|default(0) }}</span>
1224
+ <span class="stat-label">Crashes</span>
1225
+ </div>
1226
+ </div>
1227
+ <div class="col-lg-2 col-md-4 col-sm-6">
1228
+ <div class="text-center">
1229
+ <i class="bi bi-clock text-warning" style="font-size: 2rem;"></i>
1230
+ <span class="stat-value value-warning">{{ total_anr_count|default(0) }}</span>
1231
+ <span class="stat-label">ANRs</span>
1232
+ </div>
1233
+ </div>
1234
+ <div class="col-lg-2 col-md-4 col-sm-6">
1235
+ <div class="text-center">
1236
+ <i class="bi bi-pie-chart text-info" style="font-size: 2rem;"></i>
1237
+ <span class="stat-value value-highlight">{{ "%.2f"|format(coverage_percent) }}%</span>
1238
+ <span class="stat-label">Activity Coverage</span>
1239
+ </div>
1240
+ </div>
1241
+ <div class="col-lg-2 col-md-4 col-sm-6">
1242
+ <div class="text-center">
1243
+ <i class="bi bi-list-check text-primary" style="font-size: 2rem;"></i>
1244
+ <span class="stat-value value-highlight">{{ all_properties_count }}</span>
1245
+ <span class="stat-label">All Properties</span>
1246
+ </div>
1247
+ </div>
1248
+ <div class="col-lg-2 col-md-4 col-sm-6">
1249
+ <div class="text-center">
1250
+ <i class="bi bi-check-square text-success" style="font-size: 2rem;"></i>
1251
+ <span class="stat-value value-success">{{ executed_properties_count }}</span>
1252
+ <span class="stat-label">Executed Properties</span>
1253
+ </div>
1254
+ </div>
1255
+ </div>
1256
+
1211
1257
  <!-- Merge Information Section -->
1212
1258
  {% if merge_info %}
1213
- <div class="merge-info-section mb-4">
1259
+ <div class="merge-info-section mt-4">
1214
1260
  <div class="merge-info-card">
1215
1261
  <!-- Collapsible Header -->
1216
1262
  <div class="merge-info-header" data-bs-toggle="collapse" data-bs-target="#mergeInfoCollapse" aria-expanded="false" aria-controls="mergeInfoCollapse">
@@ -1261,52 +1307,6 @@
1261
1307
  </div>
1262
1308
  </div>
1263
1309
  {% endif %}
1264
-
1265
- <!-- Statistics Cards -->
1266
- <div class="row g-4">
1267
- <div class="col-lg-2 col-md-4 col-sm-6">
1268
- <div class="text-center">
1269
- <i class="bi bi-bug text-danger" style="font-size: 2rem;"></i>
1270
- <span class="stat-value value-danger">{{ bugs_found }}</span>
1271
- <span class="stat-label">Bugs Found</span>
1272
- </div>
1273
- </div>
1274
- <div class="col-lg-2 col-md-4 col-sm-6">
1275
- <div class="text-center">
1276
- <i class="bi bi-x-circle text-danger" style="font-size: 2rem;"></i>
1277
- <span class="stat-value value-danger">{{ total_crash_count|default(0) }}</span>
1278
- <span class="stat-label">Crashes</span>
1279
- </div>
1280
- </div>
1281
- <div class="col-lg-2 col-md-4 col-sm-6">
1282
- <div class="text-center">
1283
- <i class="bi bi-clock text-warning" style="font-size: 2rem;"></i>
1284
- <span class="stat-value value-warning">{{ total_anr_count|default(0) }}</span>
1285
- <span class="stat-label">ANRs</span>
1286
- </div>
1287
- </div>
1288
- <div class="col-lg-2 col-md-4 col-sm-6">
1289
- <div class="text-center">
1290
- <i class="bi bi-pie-chart text-info" style="font-size: 2rem;"></i>
1291
- <span class="stat-value value-highlight">{{ "%.2f"|format(coverage_percent) }}%</span>
1292
- <span class="stat-label">Activity Coverage</span>
1293
- </div>
1294
- </div>
1295
- <div class="col-lg-2 col-md-4 col-sm-6">
1296
- <div class="text-center">
1297
- <i class="bi bi-list-check text-primary" style="font-size: 2rem;"></i>
1298
- <span class="stat-value value-highlight">{{ all_properties_count }}</span>
1299
- <span class="stat-label">All Properties</span>
1300
- </div>
1301
- </div>
1302
- <div class="col-lg-2 col-md-4 col-sm-6">
1303
- <div class="text-center">
1304
- <i class="bi bi-check-square text-success" style="font-size: 2rem;"></i>
1305
- <span class="stat-value value-success">{{ executed_properties_count }}</span>
1306
- <span class="stat-label">Executed Properties</span>
1307
- </div>
1308
- </div>
1309
- </div>
1310
1310
  </div>
1311
1311
  </div>
1312
1312
  </div>
kea2/u2Driver.py CHANGED
@@ -220,7 +220,7 @@ class StaticXpathUiObject(u2.xpath.XPathSelector):
220
220
  source = self.session.get_page_source()
221
221
  return len(self.selector.all(source)) > 0
222
222
 
223
- def __and__(self, value) -> 'StaticXpathUiObjectr':
223
+ def __and__(self, value) -> 'StaticXpathUiObject':
224
224
  s = u2.xpath.XPathSelector(self.selector)
225
225
  s._next_xpath = u2.xpath.XPathSelector.create(value.selector)
226
226
  s._operator = u2.xpath.Operator.AND
@@ -288,7 +288,7 @@ class StaticXpathUiObject(u2.xpath.XPathSelector):
288
288
  self.selector = new
289
289
  return self
290
290
 
291
- def get(self, timeout=None) -> "XMLElement":
291
+ def get(self, timeout=None) -> "u2.xpath.XMLElement":
292
292
  """
293
293
  Get first matched element
294
294
 
@@ -343,7 +343,15 @@ class _HindenWidgetFilter:
343
343
  self._nodes = []
344
344
 
345
345
  self.idx = rtree.index.Index()
346
- self.set_covered_attr(root)
346
+ try:
347
+ self.set_covered_attr(root)
348
+ except Exception as e:
349
+ import traceback, uuid
350
+ traceback.print_exc()
351
+ logger.error(f"Error in setting covered widgets")
352
+ with open(f"kea2_error_tree_{uuid.uuid4().hex}.xml", "wb") as f:
353
+ xml_bytes = etree.tostring(root, pretty_print=True, encoding="utf-8", xml_declaration=True)
354
+ f.write(xml_bytes)
347
355
 
348
356
  # xml_bytes = etree.tostring(root, pretty_print=True, encoding="utf-8", xml_declaration=True)
349
357
  # with open("filtered_tree.xml", "wb") as f:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Kea2-python
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: A python library for supporting and customizing automated UI testing for mobile apps
5
5
  Author-email: Xixian Liang <xixian@stu.ecnu.edu.cn>
6
6
  Requires-Python: >=3.8
@@ -39,6 +39,7 @@ The group has reached its capacity. Please contact Xixian Liang at [xixian@stu.e
39
39
  <div align="center">
40
40
  <a href="https://en.wikipedia.org/wiki/Kea">Kea2's logo: A large parrot skilled in finding "bugs"</a>
41
41
  </div>
42
+ </br>
42
43
 
43
44
  Kea2 is an easy-to-use tool for fuzzing mobile apps. Its key *novelty* is able to fuse automated UI testing with scripts (usually written by human), thus empowering automated UI testing with human intelligence for effectively finding *crashing bugs* as well as *non-crashing functional (logic) bugs*.
44
45
 
@@ -110,6 +111,11 @@ Find Kea2's options by running
110
111
  kea2 -h
111
112
  ```
112
113
 
114
+ Upgrade Kea2 to its latest version if you already installed Kea2 before:
115
+ ```bash
116
+ python3 -m pip install -U kea2-python
117
+ ```
118
+
113
119
  ## Quick Test
114
120
 
115
121
  Kea2 connects to and runs on Android devices. We recommend you to do a quick test to ensure that Kea2 is compatible with your devices.
@@ -235,7 +241,15 @@ For the preceding always-holding property, we can write the following script to
235
241
  ```
236
242
  > We use [hypothesis](https://github.com/HypothesisWorks/hypothesis) to generate random texts.
237
243
 
238
- You can run this example by using the similar command line in Feature 2.
244
+ You can run this example by using the similar command line in Feature 2.
245
+
246
+ ## Test Reports(测试报告)
247
+
248
+ Kea2 automatically generates comprehensive HTML test reports after each testing session.
249
+
250
+ The reports support both single test runs and merged analysis of multiple test sessions, making it easy to track testing progress and identify issues.
251
+
252
+ - [View detailed test report documentation](docs/test_report_introduction.md)
239
253
 
240
254
  ## Documentations(更多文档)
241
255
 
@@ -1,21 +1,21 @@
1
1
  kea2/__init__.py,sha256=JFJjqgf5KB4bXUFQ3upkEug0cFMFIk9p3OHV9vzulHw,75
2
2
  kea2/absDriver.py,sha256=NzmsLs1Ojz-yEXctGAqj7aKBwAQW19zd83l65RABCe8,1288
3
3
  kea2/adbUtils.py,sha256=zi0T0_g44xZQZe3XYzBsuh7VTHpdZ4dd6yKi-p7BTYI,19939
4
- kea2/bug_report_generator.py,sha256=qHwHupANp5-IZXlpSnYy5rkf07BXu2QvvfWZzJWtc6k,42590
4
+ kea2/bug_report_generator.py,sha256=gASx3AasGWAufb4A8T4dv0-22knu7h24Z9M9NBSzy24,44107
5
5
  kea2/cli.py,sha256=MccJhY8VPZa1rMAbirm3dmbzDx1lf2w3zrpF1ZUq2m0,6481
6
6
  kea2/fastbotManager.py,sha256=pGuAH-X26nOy2Qj6Hg5aoMxJx4KfsRk6bj6nhcPENGc,8158
7
- kea2/keaUtils.py,sha256=KRBYI6Vn36liKj8jFSH0W-ktGgHr-0VdC3xiX_mCF5E,25617
7
+ kea2/keaUtils.py,sha256=zfTmG23KmWmf5b71rrPTxwnpZhZ6gdlLD9eIhjAZv4Y,25834
8
8
  kea2/kea_launcher.py,sha256=M9TMCdgkteCWO5iBxJRDRvb7dikanoPf3jdicCEurU8,6268
9
9
  kea2/logWatcher.py,sha256=Dp6OzvLSuWYw0AqdcPDqfotaRZQgpF8S49LInGsAWp8,2599
10
10
  kea2/report_merger.py,sha256=0b-g59pdrsJDwVNek02ouu1utuu_Sd_1oEMQa4e23xI,24884
11
11
  kea2/resultSyncer.py,sha256=9kb3H0Innwj7oPboDDTf97nbjam7EP6HYxywR9B8SvM,2437
12
- kea2/u2Driver.py,sha256=SfHkUAp6uHHSllPZmKs7C8JaEGGuX9DPWgshiqyWI5k,19775
12
+ kea2/u2Driver.py,sha256=k1HGH4MF5BbSpohMbK9yn-VpsDzGcYTQLjppHVzHx28,20182
13
13
  kea2/utils.py,sha256=x0VTGweW-XShG9MuwZDMP13SBg8jQXYa7e0AXdwYX38,3270
14
14
  kea2/assets/fastbot-thirdpart.jar,sha256=0SZ_OoZFWDGMnazgXKceHgKvXdUDoIa3Gb2bcifaikk,85664
15
15
  kea2/assets/framework.jar,sha256=rTluOJJKj2DFwh7ascXso1udYdWv00BxBwSQ3Vmv-fw,1149240
16
16
  kea2/assets/kea2-thirdpart.jar,sha256=HYdtG2gqDLuLb72dpK3lX-Y6QUNTrJ-bfQopU5aWpfo,359346
17
17
  kea2/assets/monkeyq.jar,sha256=4_WLifmU9q5noqMofZWW15Gh8kcuVouNrI-Ca5_g-BM,113104
18
- kea2/assets/quicktest.py,sha256=TJj9GaRioFrijU9PMLpyZY8S07db67UZFBr5G-aQY80,3000
18
+ kea2/assets/quicktest.py,sha256=BgTul5jfSBCh6hVSMRmur61M6_KNTkzIT6Bdff72TE4,3009
19
19
  kea2/assets/fastbot_configs/abl.strings,sha256=Rn8_YEbVGOJqndIY_-kWnR5NaoFI-cuB-ij10Ddhl90,75
20
20
  kea2/assets/fastbot_configs/awl.strings,sha256=-j4980GoWQxGOM9ijAwXPQmziCwFBZJFmuiv2tOEaYI,101
21
21
  kea2/assets/fastbot_configs/max.config,sha256=rBgR4mdgBzqVPQ2lZaXqx2WN6tDzhe-FNizm4Y7tyA8,226
@@ -28,11 +28,11 @@ kea2/assets/fastbot_libs/arm64-v8a/libfastbot_native.so,sha256=tAFrG73pJi7XakRxS
28
28
  kea2/assets/fastbot_libs/armeabi-v7a/libfastbot_native.so,sha256=UV8bhaiPoPKdd3q0vj3kSZqPR9anllai_tz_2QkMMbQ,1335372
29
29
  kea2/assets/fastbot_libs/x86/libfastbot_native.so,sha256=k-aw1gEXRWMKZRNHIggKNuZy0wC1y2BnveJGEIO6rbo,2036856
30
30
  kea2/assets/fastbot_libs/x86_64/libfastbot_native.so,sha256=tiofhlf4uMQcU5WAvrdLgTBME0lb83hVUoGtTwxmE8A,2121416
31
- kea2/templates/bug_report_template.html,sha256=XoLAqiPfk5asvSRhhI5nCity8Z77rxMBGT2_8rFrJP4,151729
32
- kea2/templates/merged_bug_report_template.html,sha256=awhMSURsP6Gpw0YHTs3xWZMQO7dhi0yM3H2JYHQ5_zA,135668
33
- kea2_python-0.3.2.dist-info/licenses/LICENSE,sha256=nM9PPjcsXVo5SzNsjRqWgA-gdJlwqZZcRDSC6Qf6bVE,2034
34
- kea2_python-0.3.2.dist-info/METADATA,sha256=dD3gescsC5Q-R8OZYFfvbiYBDhvJefFXzopffB2EPVI,18498
35
- kea2_python-0.3.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
36
- kea2_python-0.3.2.dist-info/entry_points.txt,sha256=mFX06TyxXiUAJQ6JZn8QHzfn8n5R8_KJ5W-pTm_fRCA,39
37
- kea2_python-0.3.2.dist-info/top_level.txt,sha256=TsgNH4PQoNOVhegpO7AcjutMVWp6Z4KDL1pBH9FnMmk,5
38
- kea2_python-0.3.2.dist-info/RECORD,,
31
+ kea2/templates/bug_report_template.html,sha256=amZUwlJSg1jzpb1-RB0W6fzwXYZBQK-4SHdhj6LYSbo,152983
32
+ kea2/templates/merged_bug_report_template.html,sha256=iWoXxvN3YQzCabi7BTP4sGl2F6LQrR3_HcG0aD3fHtk,135668
33
+ kea2_python-0.3.4.dist-info/licenses/LICENSE,sha256=nM9PPjcsXVo5SzNsjRqWgA-gdJlwqZZcRDSC6Qf6bVE,2034
34
+ kea2_python-0.3.4.dist-info/METADATA,sha256=owA_RN6ZzlDdCqzVoNoAbsUcvpXNXixhFUiAwZpjKHQ,18983
35
+ kea2_python-0.3.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
36
+ kea2_python-0.3.4.dist-info/entry_points.txt,sha256=mFX06TyxXiUAJQ6JZn8QHzfn8n5R8_KJ5W-pTm_fRCA,39
37
+ kea2_python-0.3.4.dist-info/top_level.txt,sha256=TsgNH4PQoNOVhegpO7AcjutMVWp6Z4KDL1pBH9FnMmk,5
38
+ kea2_python-0.3.4.dist-info/RECORD,,