1
2"""
3    Copyright Kristjan Kongas 2020
4
5    Boost Software License - Version 1.0 - August 17th, 2003
6
7    Permission is hereby granted, free of charge, to any person or organization
8    obtaining a copy of the software and accompanying documentation covered by
9    this license (the "Software") to use, reproduce, display, distribute,
10    execute, and transmit the Software, and to prepare derivative works of the
11    Software, and to permit third-parties to whom the Software is furnished to
12    do so, all subject to the following:
13
14    The copyright notices in the Software and this entire statement, including
15    the above license grant, this restriction and the following disclaimer,
16    must be included in all copies of the Software, in whole or in part, and
17    all derivative works of the Software, unless such copies or derivative
18    works are solely in the form of machine-executable object code generated by
19    a source language processor.
20
21    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23    FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24    SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25    FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27    DEALINGS IN THE SOFTWARE.
28"""
29
30import subprocess, json
31from pathlib import Path
32
33fire_failure_code = 1
34
35class assert_runner:
36    test_count = 0
37    check_count = 0
38
39    def __init__(self, pth):
40        self.pth = str(pth)
41        assert_runner.test_count += 1
42        self.help_success("-h")
43        self.help_success("--help")
44
45    def equal(self, cmd, out):
46        stdout, stderr, code = self.run(cmd)
47        assert code == 0
48        assert stdout == self.remove_newline(out.strip())
49        assert stderr == ""
50        assert_runner.check_count += 1
51
52    def handled_failure(self, cmd):
53        stdout, stderr, code = self.run(cmd)
54        assert code == fire_failure_code
55        assert stdout == ""
56        assert stderr != ""
57        assert_runner.check_count += 1
58
59    def help_success(self, cmd):
60        stdout, stderr, code = self.run(cmd)
61        assert code == 0
62        assert stdout == ""
63        assert stderr != ""
64        assert_runner.check_count += 1
65
66    def run(self, cmd):
67        result = subprocess.run([self.pth] + cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
68        stdout = self.remove_newline(self.b2str(result.stdout.strip()))
69        stderr = self.remove_newline(self.b2str(result.stderr.strip()))
70        code = result.returncode
71        return stdout, stderr, code
72
73    def remove_newline(self, strn):
74        return strn.replace("\r", "").replace("\n", "")
75
76    def b2str(self, b):
77        return str(b, "utf-8")
78
79
80def run_all_combinations(path_prefix):
81    runner = assert_runner(path_prefix / "all_combinations")
82
83    runner.equal("0 -i=0", "")
84    runner.equal("0 1 -i=0 --def-r=0.0 --opt-s=string", "")
85    runner.equal("0 1 -i 0 --def-r 0.0 --opt-s string", "")
86
87
88def run_basic(path_prefix):
89    runner = assert_runner(path_prefix / "basic")
90
91    runner.equal("-x 3 -y 4", "3 + 4 = 7")
92    runner.equal("-x -3 -y 3", "-3 + 3 = 0")
93    runner.equal("-x=-3 -y=3", "-3 + 3 = 0")
94    runner.equal("-x3 -y4", "3 + 4 = 7")
95    runner.handled_failure("")
96    runner.handled_failure("-x 3")
97    runner.handled_failure("-y 4")
98    runner.handled_failure("-x test")
99    runner.handled_failure("-x")
100    runner.handled_failure("--undefined 0")
101    runner.help_success("-x 0 -h")
102    runner.help_success("-h --undefined")
103
104
105def run_flag(path_prefix):
106    runner = assert_runner(path_prefix / "flag")
107
108    runner.equal("", "flag-a: false   flag-b: false")
109    runner.equal("-a -b", "flag-a: true   flag-b: true")
110    runner.equal("-ab", "flag-a: true   flag-b: true")
111    runner.equal("--flag-a", "flag-a: true   flag-b: false")
112    runner.equal("--flag-b", "flag-a: false   flag-b: true")
113    runner.handled_failure("-a 1")
114
115
116def run_optional_and_default(path_prefix):
117    runner = assert_runner(path_prefix / "optional_and_default")
118
119    runner.equal("", "optional: [no value]\ndefault: 0")
120    runner.equal("--default 1", "optional: [no value]\ndefault: 1")
121    runner.equal("--optional -1", "optional: -1\ndefault: 0")
122    runner.equal("--optional -1 --default 1", "optional: -1\ndefault: 1")
123
124
125def run_positional(path_prefix):
126    runner = assert_runner(path_prefix / "positional")
127
128    runner.handled_failure("")
129    runner.handled_failure("test")
130    runner.equal("2", "2 0")
131    runner.equal("2 3", "2 3")
132    runner.handled_failure("2 3 4")
133    runner.equal("-1 -3", "-1 -3")
134
135
136def run_variadic(path_prefix):
137    runner = assert_runner(path_prefix / "variadic")
138
139    runner.equal("", "\n")
140    runner.equal("b a", "b a\n")
141    runner.equal("b a -o", "b\na\n")
142    runner.equal("b a -s", "a b\n")
143    runner.equal("b a -os", "a\nb\n")
144    runner.equal("a -- -b", "a -b\n")
145
146
147def run_no_exceptions(path_prefix):
148    runner = assert_runner(path_prefix / "no_exceptions")
149
150    runner.equal("", "\n")
151    runner.equal("1 2", "1 2 \n")
152    runner.equal("1 2 -r=2", "1 2 \n1 2 \n")
153    stdout, stderr, code = runner.run("-h")
154    assert stderr.find("Notes") != -1
155
156
157def get_path_prefix(subdir):
158    cur_dir = Path(__file__).absolute().parent
159    with (cur_dir / "build_dirs.json").open("r") as json_file:
160        json_obj = json.load(json_file)
161        return cur_dir / json_obj[subdir]
162
163
164def main():
165    path_prefix = get_path_prefix("examples")
166
167    print("Running tests in {} ...".format(path_prefix), end="")
168
169    run_all_combinations(path_prefix)
170    run_basic(path_prefix)
171    run_flag(path_prefix)
172    run_optional_and_default(path_prefix)
173    run_positional(path_prefix)
174    run_variadic(path_prefix)
175
176    run_no_exceptions(path_prefix)
177
178    print(" SUCCESS! (ran {} tests with {} checks)".format(assert_runner.test_count, assert_runner.check_count))
179
180
181if __name__ == "__main__":
182    main()
183