TipitakaReadingSliceTest.php 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. <?php
  2. use App\Services\V3\TipitakaReadingService;
  3. /**
  4. * sliceByBytes() 是纯函数,不碰数据库。段落数上限要造上千段才看得出来,走 HTTP
  5. * 会真的去渲染每一段,所以这里直接对着方法本身测。
  6. *
  7. * 逻辑在 Service 里,所以不必再为了拿到它去造控制器的匿名子类——
  8. * 这正是「业务逻辑一律进 Service」买到的好处之一。
  9. *
  10. * @param array<int, int> $paras 段落号,统一当作 book 9000
  11. * @param array<int, int> $lengths 段落号 => 字节数
  12. * @return array<int, int> 切出来的段落号
  13. */
  14. function sliceParagraphs(array $paras, array $lengths, int $limit): array
  15. {
  16. $candidates = array_map(fn (int $para) => ['book' => 9000, 'para' => $para], $paras);
  17. $slice = app(TipitakaReadingService::class)->sliceByBytes($candidates, [9000 => $lengths], $limit);
  18. return array_column($slice, 'para');
  19. }
  20. it('caps a byte-mode block at 200 paragraphs however short the paragraphs are', function () {
  21. // 1000 段,每段 1 字节;不设段落上限的话 5000b 会把整章切成一块
  22. $paras = range(1, 1000);
  23. $lengths = array_fill_keys($paras, 1);
  24. expect(sliceParagraphs($paras, $lengths, 5000))->toBe(range(1, 200))
  25. ->and(sliceParagraphs(range(201, 1000), $lengths, 5000))->toBe(range(201, 400))
  26. ->and(sliceParagraphs(range(901, 1000), $lengths, 5000))->toBe(range(901, 1000));
  27. });
  28. it('still breaks on the byte limit when paragraphs are long enough', function () {
  29. $paras = range(1, 10);
  30. $lengths = array_fill_keys($paras, 100);
  31. expect(sliceParagraphs($paras, $lengths, 250))->toBe([1, 2, 3])
  32. ->and(sliceParagraphs(range(4, 10), $lengths, 250))->toBe([4, 5, 6]);
  33. });
  34. it('never returns an empty byte-mode block when lengths are missing', function () {
  35. // pali_texts 里查不到长度时按 0 算,靠段落数上限收口,不会死循环也不会空块
  36. expect(sliceParagraphs(range(1, 1000), [], 5000))->toBe(range(1, 200))
  37. ->and(sliceParagraphs(range(801, 1000), [], 5000))->toBe(range(801, 1000));
  38. });
  39. it('returns an empty block for no candidates', function () {
  40. expect(sliceParagraphs([], [], 5000))->toBe([]);
  41. });