|
3 | 3 | import pytest |
4 | 4 |
|
5 | 5 | from great_docs._versioning import ( |
| 6 | + BADGE_EXPIRY_NEVER, |
| 7 | + BadgeExpiry, |
6 | 8 | VersionEntry, |
7 | 9 | build_version_map, |
8 | 10 | evaluate_version_expr, |
9 | 11 | extract_page_versions, |
10 | 12 | get_latest_version, |
| 13 | + is_badge_expired, |
11 | 14 | page_matches_version, |
| 15 | + parse_badge_expiry, |
12 | 16 | parse_versions_config, |
13 | 17 | process_version_fences, |
14 | 18 | ) |
@@ -639,3 +643,189 @@ def test_prerelease_and_eol_flags(self): |
639 | 643 | # Non-flagged version should not have the keys |
640 | 644 | assert "prerelease" not in result["versions"][1] |
641 | 645 | assert "eol" not in result["versions"][1] |
| 646 | + |
| 647 | + |
| 648 | +# --------------------------------------------------------------------------- |
| 649 | +# parse_badge_expiry |
| 650 | +# --------------------------------------------------------------------------- |
| 651 | + |
| 652 | + |
| 653 | +class TestParseBadgeExpiry: |
| 654 | + def test_none(self): |
| 655 | + assert parse_badge_expiry(None) is BADGE_EXPIRY_NEVER |
| 656 | + |
| 657 | + def test_never_string(self): |
| 658 | + result = parse_badge_expiry("never") |
| 659 | + assert result.mode == "never" |
| 660 | + |
| 661 | + def test_never_case_insensitive(self): |
| 662 | + assert parse_badge_expiry("Never").mode == "never" |
| 663 | + |
| 664 | + def test_releases(self): |
| 665 | + result = parse_badge_expiry("3 releases") |
| 666 | + assert result.mode == "releases" |
| 667 | + assert result.value == 3 |
| 668 | + |
| 669 | + def test_release_singular(self): |
| 670 | + result = parse_badge_expiry("1 release") |
| 671 | + assert result.mode == "releases" |
| 672 | + assert result.value == 1 |
| 673 | + |
| 674 | + def test_minor_releases(self): |
| 675 | + result = parse_badge_expiry("2 minor releases") |
| 676 | + assert result.mode == "minor_releases" |
| 677 | + assert result.value == 2 |
| 678 | + |
| 679 | + def test_days(self): |
| 680 | + result = parse_badge_expiry("180 days") |
| 681 | + assert result.mode == "days" |
| 682 | + assert result.value == 180 |
| 683 | + |
| 684 | + def test_day_singular(self): |
| 685 | + result = parse_badge_expiry("1 day") |
| 686 | + assert result.mode == "days" |
| 687 | + assert result.value == 1 |
| 688 | + |
| 689 | + def test_iso_date(self): |
| 690 | + result = parse_badge_expiry("2026-06-01") |
| 691 | + assert result.mode == "date" |
| 692 | + assert result.value == "2026-06-01" |
| 693 | + |
| 694 | + def test_version_tag(self): |
| 695 | + result = parse_badge_expiry("0.8") |
| 696 | + assert result.mode == "version" |
| 697 | + assert result.value == "0.8" |
| 698 | + |
| 699 | + def test_version_tag_with_v_prefix(self): |
| 700 | + result = parse_badge_expiry("v1.2") |
| 701 | + assert result.mode == "version" |
| 702 | + assert result.value == "v1.2" |
| 703 | + |
| 704 | + |
| 705 | +# --------------------------------------------------------------------------- |
| 706 | +# is_badge_expired |
| 707 | +# --------------------------------------------------------------------------- |
| 708 | + |
| 709 | + |
| 710 | +class TestIsBadgeExpired: |
| 711 | + @pytest.fixture |
| 712 | + def versions(self) -> list[VersionEntry]: |
| 713 | + return parse_versions_config( |
| 714 | + [ |
| 715 | + {"tag": "dev", "label": "dev", "prerelease": True}, |
| 716 | + {"tag": "0.7", "label": "0.7.0"}, |
| 717 | + {"tag": "0.6", "label": "0.6.0"}, |
| 718 | + {"tag": "0.5", "label": "0.5.0"}, |
| 719 | + {"tag": "0.4", "label": "0.4.0"}, |
| 720 | + {"tag": "0.3", "label": "0.3.0"}, |
| 721 | + ] |
| 722 | + ) |
| 723 | + |
| 724 | + def test_never_not_expired(self, versions): |
| 725 | + assert is_badge_expired("0.3", versions[1], versions, BADGE_EXPIRY_NEVER) is False |
| 726 | + |
| 727 | + # --- releases mode --- |
| 728 | + |
| 729 | + def test_releases_not_expired_same_version(self, versions): |
| 730 | + expiry = BadgeExpiry(mode="releases", value=3) |
| 731 | + target = versions[5] # 0.3 |
| 732 | + assert is_badge_expired("0.3", target, versions, expiry) is False |
| 733 | + |
| 734 | + def test_releases_not_expired_within_window(self, versions): |
| 735 | + expiry = BadgeExpiry(mode="releases", value=3) |
| 736 | + target = versions[3] # 0.5 — 2 releases after 0.3 |
| 737 | + assert is_badge_expired("0.3", target, versions, expiry) is False |
| 738 | + |
| 739 | + def test_releases_expired_at_boundary(self, versions): |
| 740 | + expiry = BadgeExpiry(mode="releases", value=3) |
| 741 | + target = versions[2] # 0.6 — 3 releases after 0.3 |
| 742 | + assert is_badge_expired("0.3", target, versions, expiry) is True |
| 743 | + |
| 744 | + def test_releases_expired_past_boundary(self, versions): |
| 745 | + expiry = BadgeExpiry(mode="releases", value=3) |
| 746 | + target = versions[1] # 0.7 — 4 releases after 0.3 |
| 747 | + assert is_badge_expired("0.3", target, versions, expiry) is True |
| 748 | + |
| 749 | + # --- minor_releases mode --- |
| 750 | + |
| 751 | + def test_minor_releases_skips_prerelease(self, versions): |
| 752 | + # dev is prerelease, so only 0.7-0.3 count |
| 753 | + expiry = BadgeExpiry(mode="minor_releases", value=3) |
| 754 | + target = versions[2] # 0.6 — 3 non-pre releases after 0.3 |
| 755 | + assert is_badge_expired("0.3", target, versions, expiry) is True |
| 756 | + |
| 757 | + def test_minor_releases_not_expired(self, versions): |
| 758 | + expiry = BadgeExpiry(mode="minor_releases", value=3) |
| 759 | + target = versions[3] # 0.5 — 2 non-pre releases after 0.3 |
| 760 | + assert is_badge_expired("0.3", target, versions, expiry) is False |
| 761 | + |
| 762 | + def test_minor_releases_prerelease_target_falls_back_to_latest(self, versions): |
| 763 | + # dev (prerelease) should behave like the latest non-prerelease (0.7) |
| 764 | + expiry = BadgeExpiry(mode="minor_releases", value=3) |
| 765 | + target_dev = versions[0] # dev |
| 766 | + target_07 = versions[1] # 0.7 |
| 767 | + assert is_badge_expired("0.3", target_dev, versions, expiry) == is_badge_expired( |
| 768 | + "0.3", target_07, versions, expiry |
| 769 | + ) |
| 770 | + |
| 771 | + # --- version mode --- |
| 772 | + |
| 773 | + def test_version_not_expired_before_threshold(self, versions): |
| 774 | + expiry = BadgeExpiry(mode="version", value="0.6") |
| 775 | + target = versions[3] # 0.5 |
| 776 | + assert is_badge_expired("0.3", target, versions, expiry) is False |
| 777 | + |
| 778 | + def test_version_expired_at_threshold(self, versions): |
| 779 | + expiry = BadgeExpiry(mode="version", value="0.6") |
| 780 | + target = versions[2] # 0.6 |
| 781 | + assert is_badge_expired("0.3", target, versions, expiry) is True |
| 782 | + |
| 783 | + def test_version_expired_after_threshold(self, versions): |
| 784 | + expiry = BadgeExpiry(mode="version", value="0.6") |
| 785 | + target = versions[1] # 0.7 |
| 786 | + assert is_badge_expired("0.3", target, versions, expiry) is True |
| 787 | + |
| 788 | + # --- date mode --- |
| 789 | + |
| 790 | + def test_date_not_expired_future(self, versions): |
| 791 | + expiry = BadgeExpiry(mode="date", value="2099-01-01") |
| 792 | + assert is_badge_expired("0.3", versions[1], versions, expiry) is False |
| 793 | + |
| 794 | + def test_date_expired_past(self, versions): |
| 795 | + expiry = BadgeExpiry(mode="date", value="2020-01-01") |
| 796 | + assert is_badge_expired("0.3", versions[1], versions, expiry) is True |
| 797 | + |
| 798 | + # --- days mode --- |
| 799 | + |
| 800 | + def test_days_no_released_date(self, versions): |
| 801 | + expiry = BadgeExpiry(mode="days", value=90) |
| 802 | + # No released date → fail open |
| 803 | + assert is_badge_expired("0.3", versions[1], versions, expiry) is False |
| 804 | + |
| 805 | + def test_days_expired(self): |
| 806 | + versions = parse_versions_config( |
| 807 | + [ |
| 808 | + {"tag": "0.5", "label": "0.5.0"}, |
| 809 | + {"tag": "0.3", "label": "0.3.0", "released": "2020-01-01"}, |
| 810 | + ] |
| 811 | + ) |
| 812 | + expiry = BadgeExpiry(mode="days", value=90) |
| 813 | + assert is_badge_expired("0.3", versions[0], versions, expiry) is True |
| 814 | + |
| 815 | + def test_days_not_expired(self): |
| 816 | + versions = parse_versions_config( |
| 817 | + [ |
| 818 | + {"tag": "0.5", "label": "0.5.0"}, |
| 819 | + {"tag": "0.3", "label": "0.3.0", "released": "2099-01-01"}, |
| 820 | + ] |
| 821 | + ) |
| 822 | + expiry = BadgeExpiry(mode="days", value=90) |
| 823 | + assert is_badge_expired("0.3", versions[0], versions, expiry) is False |
| 824 | + |
| 825 | + # --- unknown badge version --- |
| 826 | + |
| 827 | + def test_unknown_badge_version(self, versions): |
| 828 | + expiry = BadgeExpiry(mode="releases", value=1) |
| 829 | + assert is_badge_expired("9.9", versions[1], versions, expiry) is False |
| 830 | + |
| 831 | + # --- changed/deprecated not affected (tested via expand_version_badges) --- |
0 commit comments