test_runner.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import importlib.util
  2. from pathlib import Path
  3. import sys
  4. import unittest
  5. RUNNER_PATH = Path(__file__).parents[1] / "runner.py"
  6. SPEC = importlib.util.spec_from_file_location("legado_android_runner", RUNNER_PATH)
  7. runner = importlib.util.module_from_spec(SPEC)
  8. assert SPEC.loader is not None
  9. SPEC.loader.exec_module(runner)
  10. class ScenarioValidationTest(unittest.TestCase):
  11. def test_repository_scenario_is_valid(self):
  12. scenario = runner.load_scenario("reader/page-turn")
  13. self.assertEqual("long-chapter-v1", scenario["fixture"])
  14. def test_rejects_unknown_action(self):
  15. scenario = {
  16. "schemaVersion": 1,
  17. "name": "reader/page-turn",
  18. "fixture": "long-chapter-v1",
  19. "readyMarker": "marker",
  20. "actions": [{"type": "tap"}],
  21. "assertions": ["reader_ready"],
  22. }
  23. with self.assertRaises(runner.ScenarioError):
  24. runner.validate_scenario(scenario)
  25. def test_rejects_missing_fixture(self):
  26. with self.assertRaises(runner.ScenarioError):
  27. runner.validate_fixture("missing-v1")
  28. def test_rejects_invalid_fixture_before_device_work(self):
  29. fixture = {
  30. "schemaVersion": 1,
  31. "id": "broken-v1",
  32. "resetPolicy": "replace",
  33. "book": {
  34. "bookUrl": "debug://book",
  35. "name": "broken",
  36. "author": "debug",
  37. "pageMode": "simulation",
  38. "startChapter": 0,
  39. "startPosition": 0,
  40. },
  41. "chapters": [{"title": "chapter", "readyMarker": "ready", "paragraph": "text", "repeat": 0}],
  42. }
  43. with self.assertRaises(runner.ScenarioError):
  44. runner.validate_fixture_data(fixture, "broken-v1")
  45. class FailureParsingTest(unittest.TestCase):
  46. def test_ignores_crash_from_another_package(self):
  47. logcat = """FATAL EXCEPTION: main
  48. Process: com.example.other, PID: 42
  49. java.lang.IllegalStateException: unrelated
  50. """
  51. self.assertEqual("", runner.extract_crash(logcat))
  52. def test_parses_app_frame_as_inference(self):
  53. crash = """FATAL EXCEPTION: main
  54. java.lang.IndexOutOfBoundsException: Index 18 out of bounds
  55. at io.legado.app.ui.book.read.ReadBookViewModel.loadChapter(ReadBookViewModel.kt:418)
  56. """
  57. failure = runner.parse_failure(crash)
  58. self.assertEqual("uncaught_exception", failure["category"])
  59. self.assertEqual("IndexOutOfBoundsException", failure["exceptionType"])
  60. self.assertEqual("high", failure["suspectedFrame"]["confidence"])
  61. self.assertEqual(418, failure["suspectedFrame"]["line"])
  62. def test_crash_has_priority_over_assertion_failure(self):
  63. scenario = runner.load_scenario("reader/page-turn")
  64. summary, exit_code = runner.make_summary(
  65. session_id="test",
  66. scenario=scenario,
  67. fixture="long-chapter-v1",
  68. build={"status": "passed"},
  69. ready=False,
  70. activity_visible=False,
  71. content_changed=False,
  72. action_count=0,
  73. failure={"category": "uncaught_exception", "stacktraceArtifact": "crash.txt"},
  74. )
  75. self.assertEqual(runner.EXIT_CRASH, exit_code)
  76. self.assertEqual(runner.EXIT_CRASH, summary["exitCode"])
  77. class CommandDecodingTest(unittest.TestCase):
  78. def test_replaces_invalid_utf8_in_command_output(self):
  79. result = runner.run_command(
  80. [sys.executable, "-c", "import sys; sys.stdout.buffer.write(b'log\\xc0tail')"],
  81. )
  82. self.assertEqual("log\ufffdtail", result.stdout)
  83. if __name__ == "__main__":
  84. unittest.main()