1# Running the test with Python 2:
2# Be sure to install pytest version 4.6.4 (newer should also work)
3# Command in cppcheck directory:
4# python -m pytest addons/test/test-y2038.py
5#
6# Running the test with Python 3:
7# Command in cppcheck directory:
8# PYTHONPATH=./addons python3 -m pytest addons/test/test-y2038.py
9
10import sys
11import pytest
12
13from addons.y2038 import check_y2038_safe
14
15from .util import dump_create, dump_remove, convert_json_output
16
17
18TEST_SOURCE_FILES = ['./addons/test/y2038/y2038-test-1-bad-time-bits.c',
19                     './addons/test/y2038/y2038-test-2-no-time-bits.c',
20                     './addons/test/y2038/y2038-test-3-no-use-time-bits.c',
21                     './addons/test/y2038/y2038-test-4-good.c',
22                     './addons/test/y2038/y2038-test-5-good-no-time-used.c']
23
24
25def setup_module(module):
26    sys.argv.append("--cli")
27    for f in TEST_SOURCE_FILES:
28        dump_create(f)
29
30
31def teardown_module(module):
32    sys.argv.remove("--cli")
33    for f in TEST_SOURCE_FILES:
34        dump_remove(f)
35
36
37def test_1_bad_time_bits(capsys):
38    is_safe = check_y2038_safe('./addons/test/y2038/y2038-test-1-bad-time-bits.c.dump', quiet=True)
39    assert(is_safe is False)
40    captured = capsys.readouterr()
41    captured = captured.out.splitlines()
42    json_output = convert_json_output(captured)
43
44    # Has exactly one warnings of _TIME_BITS and _USE_TIME_BITS64 kind.
45    assert(len(json_output['type-bits-undef']) == 1)
46    assert(len(json_output['type-bits-not-64']) == 1)
47
48    # There are 2 unsafe calls in test source and 3 in y2038-in.h
49    unsafe_calls = json_output['unsafe-call']
50    assert(len([c for c in unsafe_calls if c['file'].endswith('h')]) == 3)
51    assert(len([c for c in unsafe_calls if c['file'].endswith('c')]) == 0)
52
53
54def test_2_no_time_bits(capsys):
55    is_safe = check_y2038_safe('./addons/test/y2038/y2038-test-2-no-time-bits.c.dump', quiet=True)
56    assert(is_safe is False)
57    captured = capsys.readouterr()
58    captured = captured.out.splitlines()
59    json_output = convert_json_output(captured)
60
61    # _USE_TIME_BITS64 defined in y2038-inc.h header, but there is not
62    # _TIME_BITS definition. Here must be appropriate warning.
63    assert(len(json_output['type-bits-undef']) == 1)
64    assert(json_output.get('type-bits-not-64') is None)
65
66    # y2038-in.h still has y2038-unsafe calls.
67    unsafe_calls = json_output['unsafe-call']
68    assert(len([c for c in unsafe_calls if c['file'].endswith('h')]) == 3)
69
70
71def test_3_no_use_time_bits(capsys):
72    is_safe = check_y2038_safe('./addons/test/y2038/y2038-test-3-no-use-time-bits.c.dump', quiet=True)
73    assert(is_safe is False)
74    captured = capsys.readouterr()
75    captured = captured.out.splitlines()
76    json_output = convert_json_output(captured)
77
78    # Included bad _USE_TIME_BITS64 definition must trigger the errors.
79    unsafe_calls = json_output['unsafe-call']
80    assert(len(unsafe_calls) == 2)
81
82
83def test_4_good(capsys):
84    is_safe = check_y2038_safe('./addons/test/y2038/y2038-test-4-good.c.dump', quiet=True)
85    # assert(is_safe is True) # FIXME: This should be a "good" example returning "True" instead of "False"
86    captured = capsys.readouterr()
87    captured = captured.out.splitlines()
88    json_output = convert_json_output(captured)
89
90    # Defined _TIME_BITS equal to 64 so that glibc knows we want Y2038 support.
91    # There are no warnings from C sources.
92    unsafe_calls = json_output['unsafe-call']
93    assert(len([c for c in unsafe_calls if c['file'].endswith('.c')]) == 0)
94
95
96def test_5_good(capsys):
97    is_safe = check_y2038_safe('./addons/test/y2038/y2038-test-5-good-no-time-used.c.dump', quiet=True)
98    assert(is_safe is True)
99    captured = capsys.readouterr()
100    captured = captured.out.splitlines()
101    json_output = convert_json_output(captured)
102
103    # There are no warnings from C sources.
104    if 'unsafe-call' in json_output:
105        unsafe_calls = json_output['unsafe-call']
106        assert(len([c for c in unsafe_calls if c['file'].endswith('.c')]) == 0)
107
108
109def test_arguments_regression():
110    args_ok = ["-t=foo", "--template=foo",
111               "-q", "--quiet",
112               "--cli"]
113    # Arguments with expected SystemExit
114    args_exit = ["--non-exists", "--non-exists-param=42", "-h", "--help"]
115
116    from addons.y2038 import get_args_parser
117
118    for arg in args_exit:
119        sys.argv.append(arg)
120        with pytest.raises(SystemExit):
121            parser = get_args_parser()
122            parser.parse_args()
123        sys.argv.remove(arg)
124
125    for arg in args_ok:
126        sys.argv.append(arg)
127        try:
128            parser = get_args_parser()
129            parser.parse_args()
130        except SystemExit:
131            pytest.fail("Unexpected SystemExit with '%s'" % arg)
132        sys.argv.remove(arg)
133