aboutsummaryrefslogtreecommitdiff
blob: 0483a35b3e649941ee32bce2fd445acbb93f7a14 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# Copyright 2018 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

import subprocess
import tempfile

from portage.const import PORTAGE_BIN_PATH
from portage.tests import TestCase


class TestEAPI7VerFuncs(TestCase):
    def _test_output(self, test_cases):
        """
        Test that commands in test_cases produce expected output.
        """
        with tempfile.NamedTemporaryFile("w") as test_script:
            test_script.write(f'source "{PORTAGE_BIN_PATH}"/eapi7-ver-funcs.sh\n')
            for cmd, exp in test_cases:
                test_script.write(f"{cmd}\n")
            test_script.flush()

            s = subprocess.Popen(
                ["bash", test_script.name],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
            )
            sout, serr = s.communicate()
            self.assertEqual(s.returncode, 0)

            for test_case, result in zip(test_cases, sout.decode().splitlines()):
                cmd, exp = test_case
                self.assertEqual(result, exp, f"{cmd} -> {result}; expected: {exp}")

    def _test_return(self, test_cases):
        """
        Test that commands in test_cases give appropriate exit codes.
        """
        with tempfile.NamedTemporaryFile("w+") as test_script:
            test_script.write(f'source "{PORTAGE_BIN_PATH}"/eapi7-ver-funcs.sh\n')
            for cmd, exp in test_cases:
                test_script.write(f"{cmd}; echo $?\n")
            test_script.flush()

            s = subprocess.Popen(
                ["bash", test_script.name],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
            )
            sout, serr = s.communicate()
            self.assertEqual(s.returncode, 0)

            for test_case, result in zip(test_cases, sout.decode().splitlines()):
                cmd, exp = test_case
                self.assertEqual(result, exp, f"{cmd} -> {result}; expected: {exp}")

    def _test_fail(self, test_cases):
        """
        Test that commands in test_cases fail.
        """

        for cmd in test_cases:
            test = f"""
source "{PORTAGE_BIN_PATH}"/eapi7-ver-funcs.sh
die() {{ exit 1; }}
{cmd}"""

            s = subprocess.Popen(
                ["bash", "-c", test], stdout=subprocess.PIPE, stderr=subprocess.PIPE
            )
            sout, serr = s.communicate()
            self.assertEqual(
                s.returncode,
                1,
                f'"{cmd}" did not fail; output: {sout.decode()}; {serr.decode()})',
            )

    def test_ver_cut(self):
        test_cases = [
            # (command, output)
            ("ver_cut 1 1.2.3", "1"),
            ("ver_cut 1-1 1.2.3", "1"),
            ("ver_cut 1-2 1.2.3", "1.2"),
            ("ver_cut 2- 1.2.3", "2.3"),
            ("ver_cut 1- 1.2.3", "1.2.3"),
            ("ver_cut 3-4 1.2.3b_alpha4", "3b"),
            ("ver_cut 5 1.2.3b_alpha4", "alpha"),
            ("ver_cut 1-2 .1.2.3", "1.2"),
            ("ver_cut 0-2 .1.2.3", ".1.2"),
            ("ver_cut 2-3 1.2.3.", "2.3"),
            ("ver_cut 2- 1.2.3.", "2.3."),
            ("ver_cut 2-4 1.2.3.", "2.3."),
        ]
        self._test_output(test_cases)

    def test_ver_rs(self):
        test_cases = [
            # (command, output)
            ("ver_rs 1 - 1.2.3", "1-2.3"),
            ("ver_rs 2 - 1.2.3", "1.2-3"),
            ("ver_rs 1-2 - 1.2.3.4", "1-2-3.4"),
            ("ver_rs 2- - 1.2.3.4", "1.2-3-4"),
            ("ver_rs 2 . 1.2-3", "1.2.3"),
            ("ver_rs 3 . 1.2.3a", "1.2.3.a"),
            ("ver_rs 2-3 - 1.2_alpha4", "1.2-alpha-4"),
            ('ver_rs 3 - 2 "" 1.2.3b_alpha4', "1.23-b_alpha4"),
            ("ver_rs 3-5 _ 4-6 - a1b2c3d4e5", "a1b_2-c-3-d4e5"),
            ("ver_rs 1 - .1.2.3", ".1-2.3"),
            ("ver_rs 0 - .1.2.3", "-1.2.3"),
        ]
        self._test_output(test_cases)

    def test_truncated_range(self):
        test_cases = [
            # (command, output)
            ("ver_cut 0-2 1.2.3", "1.2"),
            ("ver_cut 2-5 1.2.3", "2.3"),
            ("ver_cut 4 1.2.3", ""),
            ("ver_cut 0 1.2.3", ""),
            ("ver_cut 4- 1.2.3", ""),
            ("ver_rs 0 - 1.2.3", "1.2.3"),
            ("ver_rs 3 . 1.2.3", "1.2.3"),
            ("ver_rs 3- . 1.2.3", "1.2.3"),
            ("ver_rs 3-5 . 1.2.3", "1.2.3"),
        ]
        self._test_output(test_cases)

    def test_invalid_range(self):
        test_cases = [
            "ver_cut foo 1.2.3",
            "ver_rs -3 _ a1b2c3d4e5",
            "ver_rs 5-3 _ a1b2c3d4e5",
        ]
        self._test_fail(test_cases)

    def test_ver_test(self):
        test_cases = [
            # Tests from Portage's test_vercmp.py
            ("ver_test 6.0 -gt 5.0", "0"),
            ("ver_test 5.0 -gt 5", "0"),
            ("ver_test 1.0-r1 -gt 1.0-r0", "0"),
            ("ver_test 999999999999999999 -gt 999999999999999998", "0"),  # 18 digits
            ("ver_test 1.0.0 -gt 1.0", "0"),
            ("ver_test 1.0.0 -gt 1.0b", "0"),
            ("ver_test 1b -gt 1", "0"),
            ("ver_test 1b_p1 -gt 1_p1", "0"),
            ("ver_test 1.1b -gt 1.1", "0"),
            ("ver_test 12.2.5 -gt 12.2b", "0"),
            ("ver_test 4.0 -lt 5.0", "0"),
            ("ver_test 5 -lt 5.0", "0"),
            ("ver_test 1.0_pre2 -lt 1.0_p2", "0"),
            ("ver_test 1.0_alpha2 -lt 1.0_p2", "0"),
            ("ver_test 1.0_alpha1 -lt 1.0_beta1", "0"),
            ("ver_test 1.0_beta3 -lt 1.0_rc3", "0"),
            ("ver_test 1.001000000000000001 -lt 1.001000000000000002", "0"),
            ("ver_test 1.00100000000 -lt 1.001000000000000001", "0"),
            ("ver_test 999999999999999998 -lt 999999999999999999", "0"),
            ("ver_test 1.01 -lt 1.1", "0"),
            ("ver_test 1.0-r0 -lt 1.0-r1", "0"),
            ("ver_test 1.0 -lt 1.0-r1", "0"),
            ("ver_test 1.0 -lt 1.0.0", "0"),
            ("ver_test 1.0b -lt 1.0.0", "0"),
            ("ver_test 1_p1 -lt 1b_p1", "0"),
            ("ver_test 1 -lt 1b", "0"),
            ("ver_test 1.1 -lt 1.1b", "0"),
            ("ver_test 12.2b -lt 12.2.5", "0"),
            ("ver_test 4.0 -eq 4.0", "0"),
            ("ver_test 1.0 -eq 1.0", "0"),
            ("ver_test 1.0-r0 -eq 1.0", "0"),
            ("ver_test 1.0 -eq 1.0-r0", "0"),
            ("ver_test 1.0-r0 -eq 1.0-r0", "0"),
            ("ver_test 1.0-r1 -eq 1.0-r1", "0"),
            ("ver_test 1 -eq 2", "1"),
            ("ver_test 1.0_alpha -eq 1.0_pre", "1"),
            ("ver_test 1.0_beta -eq 1.0_alpha", "1"),
            ("ver_test 1 -eq 0.0", "1"),
            ("ver_test 1.0-r0 -eq 1.0-r1", "1"),
            ("ver_test 1.0-r1 -eq 1.0-r0", "1"),
            ("ver_test 1.0 -eq 1.0-r1", "1"),
            ("ver_test 1.0-r1 -eq 1.0", "1"),
            ("ver_test 1.0 -eq 1.0.0", "1"),
            ("ver_test 1_p1 -eq 1b_p1", "1"),
            ("ver_test 1b -eq 1", "1"),
            ("ver_test 1.1b -eq 1.1", "1"),
            ("ver_test 12.2b -eq 12.2", "1"),
            # A subset of tests from Paludis
            ("ver_test 1.0_alpha -gt 1_alpha", "0"),
            ("ver_test 1.0_alpha -gt 1", "0"),
            ("ver_test 1.0_alpha -lt 1.0", "0"),
            ("ver_test 1.2.0.0_alpha7-r4 -gt 1.2_alpha7-r4", "0"),
            ("ver_test 0001 -eq 1", "0"),
            ("ver_test 01 -eq 001", "0"),
            ("ver_test 0001.1 -eq 1.1", "0"),
            ("ver_test 01.01 -eq 1.01", "0"),
            ("ver_test 1.010 -eq 1.01", "0"),
            ("ver_test 1.00 -eq 1.0", "0"),
            ("ver_test 1.0100 -eq 1.010", "0"),
            ("ver_test 1-r00 -eq 1-r0", "0"),
            # Additional tests
            ("ver_test 0_rc99 -lt 0", "0"),
            ("ver_test 011 -eq 11", "0"),
            ("ver_test 019 -eq 19", "0"),
            ("ver_test 1.2 -eq 001.2", "0"),
            ("ver_test 1.2 -gt 1.02", "0"),
            ("ver_test 1.2a -lt 1.2b", "0"),
            ("ver_test 1.2_pre1 -gt 1.2_pre1_beta2", "0"),
            ("ver_test 1.2_pre1 -lt 1.2_pre1_p2", "0"),
            ("ver_test 1.00 -lt 1.0.0", "0"),
            ("ver_test 1.010 -eq 1.01", "0"),
            ("ver_test 1.01 -lt 1.1", "0"),
            ("ver_test 1.2_pre08-r09 -eq 1.2_pre8-r9", "0"),
            ("ver_test 0 -lt 576460752303423488", "0"),  # 2**59
            ("ver_test 0 -lt 9223372036854775808", "0"),  # 2**63
        ]
        self._test_return(test_cases)

    def test_invalid_test(self):
        test_cases = [
            # Bad number or ordering of arguments
            "ver_test 1",
            "ver_test 1 -lt 2 3",
            "ver_test -lt 1 2",
            # Bad operators
            'ver_test 1 "<" 2',
            "ver_test 1 lt 2",
            "ver_test 1 -foo 2",
            # Malformed versions
            'ver_test "" -ne 1',
            "ver_test 1. -ne 1",
            "ver_test 1ab -ne 1",
            "ver_test b -ne 1",
            "ver_test 1-r1_pre -ne 1",
            "ver_test 1-pre1 -ne 1",
            "ver_test 1_foo -ne 1",
            "ver_test 1_pre1.1 -ne 1",
            "ver_test 1-r1.0 -ne 1",
            "ver_test cvs.9999 -ne 9999",
        ]
        self._test_fail(test_cases)