File: y2038_test.py

package info (click to toggle)
cppcheck 2.19.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 26,688 kB
  • sloc: cpp: 272,455; python: 22,408; ansic: 8,088; sh: 1,059; makefile: 1,041; xml: 987; cs: 291
file content (206 lines) | stat: -rw-r--r-- 7,919 bytes parent folder | download
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
# Running the test with Python 2:
# Be sure to install pytest version 4.6.4 (newer should also work)
# Command in cppcheck directory:
# python -m pytest addons/test/test-y2038.py
#
# Running the test with Python 3:
# Command in cppcheck directory:
# PYTHONPATH=./addons python3 -m pytest addons/test/test-y2038.py

import sys
import pytest

from addons.y2038 import check_y2038_safe

from .util import dump_create, dump_remove, convert_json_output


TEST_SOURCE_FILES = ['./addons/test/y2038/y2038-test-1-bad-time-bits.c',
                     './addons/test/y2038/y2038-test-2-no-time-bits.c',
                     './addons/test/y2038/y2038-test-3-no-use-time-bits.c',
                     './addons/test/y2038/y2038-test-4-good.c',
                     './addons/test/y2038/y2038-test-5-good-no-time-used.c']

# Build system test file (for testing build system integration)
BUILD_SYSTEM_TEST_FILE = './addons/test/y2038/y2038-test-buildsystem.c'


def setup_module(module):
    sys.argv.append("--cli")

    # Create dumps for regular test files
    for f in TEST_SOURCE_FILES:
        dump_create(f)

    # For build system tests, we'll create dumps on-demand in each test
    # to avoid conflicts from multiple dump_create calls on the same file


def teardown_module(module):
    sys.argv.remove("--cli")
    for f in TEST_SOURCE_FILES:
        dump_remove(f)

    # Build system test dumps are cleaned up individually in each test method


def test_1_bad_time_bits(capsys):
    is_safe = check_y2038_safe('./addons/test/y2038/y2038-test-1-bad-time-bits.c.dump', quiet=True)
    assert(is_safe is False)
    captured = capsys.readouterr()
    captured = captured.out.splitlines()
    json_output = convert_json_output(captured)

    # Has exactly one warnings of _TIME_BITS and _USE_TIME_BITS64 kind.
    assert(len(json_output['type-bits-undef']) == 1)
    assert(len(json_output['type-bits-not-64']) == 1)

    # There are 2 unsafe calls in test source and 3 in y2038-in.h
    unsafe_calls = json_output['unsafe-call']
    assert(len([c for c in unsafe_calls if c['file'].endswith('h')]) == 3)
    assert(len([c for c in unsafe_calls if c['file'].endswith('c')]) == 0)


def test_2_no_time_bits(capsys):
    is_safe = check_y2038_safe('./addons/test/y2038/y2038-test-2-no-time-bits.c.dump', quiet=True)
    assert(is_safe is False)
    captured = capsys.readouterr()
    captured = captured.out.splitlines()
    json_output = convert_json_output(captured)

    # _USE_TIME_BITS64 defined in y2038-inc.h header, but there is not
    # _TIME_BITS definition. Here must be appropriate warning.
    assert(len(json_output['type-bits-undef']) == 1)
    assert(json_output.get('type-bits-not-64') is None)

    # y2038-in.h still has y2038-unsafe calls.
    unsafe_calls = json_output['unsafe-call']
    assert(len([c for c in unsafe_calls if c['file'].endswith('h')]) == 3)


def test_3_no_use_time_bits(capsys):
    is_safe = check_y2038_safe('./addons/test/y2038/y2038-test-3-no-use-time-bits.c.dump', quiet=True)
    assert(is_safe is False)
    captured = capsys.readouterr()
    captured = captured.out.splitlines()
    json_output = convert_json_output(captured)

    # Included bad _USE_TIME_BITS64 definition must trigger the errors.
    unsafe_calls = json_output['unsafe-call']
    assert(len(unsafe_calls) == 2)


def test_4_good(capsys):
    # pylint: disable-next=unused-variable - FIXME
    is_safe = check_y2038_safe('./addons/test/y2038/y2038-test-4-good.c.dump', quiet=True)
    # assert(is_safe is True) # FIXME: This should be a "good" example returning "True" instead of "False"
    captured = capsys.readouterr()
    captured = captured.out.splitlines()
    json_output = convert_json_output(captured)

    # Defined _TIME_BITS equal to 64 so that glibc knows we want Y2038 support.
    # There are no warnings from C sources.
    unsafe_calls = json_output['unsafe-call']
    assert(len([c for c in unsafe_calls if c['file'].endswith('.c')]) == 0)


def test_5_good(capsys):
    is_safe = check_y2038_safe('./addons/test/y2038/y2038-test-5-good-no-time-used.c.dump', quiet=True)
    assert(is_safe is True)
    captured = capsys.readouterr()
    captured = captured.out.splitlines()
    json_output = convert_json_output(captured)

    # There are no warnings from C sources.
    if 'unsafe-call' in json_output:
        unsafe_calls = json_output['unsafe-call']
        assert(len([c for c in unsafe_calls if c['file'].endswith('.c')]) == 0)


def test_build_system_integration():
    """Test that Y2038 flags are properly parsed from cppcheck dump file configuration"""
    from addons.y2038 import parse_dump_config

    # Test Y2038-safe configuration string (as cppcheck would generate it)
    config_string = "_TIME_BITS=64;_FILE_OFFSET_BITS=64;_USE_TIME_BITS64"
    result = parse_dump_config(config_string)
    # Y2038-safe flags should be detected
    assert result['time_bits_defined'] is True
    assert result['time_bits_value'] == 64
    assert result['use_time_bits64_defined'] is True
    assert result['file_offset_bits_defined'] is True
    assert result['file_offset_bits_value'] == 64

    # Test partial Y2038 configuration
    partial_config = "_TIME_BITS=32;_FILE_OFFSET_BITS=64"
    result = parse_dump_config(partial_config)
    # Should detect the flags with their actual values
    assert result['time_bits_defined'] is True
    assert result['time_bits_value'] == 32  # Not Y2038-safe value
    assert result['use_time_bits64_defined'] is False
    assert result['file_offset_bits_defined'] is True
    assert result['file_offset_bits_value'] == 64


def test_arguments_regression():
    args_ok = ["-t=foo", "--template=foo",
               "-q", "--quiet",
               "--cli"]
    # Arguments with expected SystemExit
    args_exit = ["--non-exists", "--non-exists-param=42", "-h", "--help"]

    from addons.y2038 import get_args_parser

    # sys.argv contains all pytest arguments - so clear all existing arguments first and restore afterwards
    sys_argv_old = sys.argv
    sys.argv = [sys.argv[0]]

    try:
        for arg in args_exit:
            sys.argv.append(arg)
            with pytest.raises(SystemExit):
                parser = get_args_parser()
                parser.parse_args()
            sys.argv.remove(arg)

        for arg in args_ok:
            sys.argv.append(arg)
            try:
                parser = get_args_parser()
                parser.parse_args()
            except SystemExit:
                pytest.fail("Unexpected SystemExit with '%s'" % arg)
            sys.argv.remove(arg)
    finally:
        sys.argv = sys_argv_old


def test_parse_dump_config():
    """Test the parse_dump_config function for cppcheck dump file integration"""
    from addons.y2038 import parse_dump_config

    # Test comprehensive Y2038 configuration
    full_config = "_TIME_BITS=64;_FILE_OFFSET_BITS=64;_USE_TIME_BITS64;OTHER_FLAG=1"
    result = parse_dump_config(full_config)

    assert result['time_bits_defined'] is True
    assert result['time_bits_value'] == 64
    assert result['use_time_bits64_defined'] is True
    assert result['file_offset_bits_defined'] is True
    assert result['file_offset_bits_value'] == 64

    # Test empty configuration
    result = parse_dump_config("")
    assert result['time_bits_defined'] is False
    assert result['time_bits_value'] is None
    assert result['use_time_bits64_defined'] is False
    assert result['file_offset_bits_defined'] is False
    assert result['file_offset_bits_value'] is None
    # Test Y2038-unsafe configuration
    unsafe_config = "_TIME_BITS=32;_FILE_OFFSET_BITS=32"
    result = parse_dump_config(unsafe_config)
    assert result['time_bits_defined'] is True
    assert result['time_bits_value'] == 32
    assert result['use_time_bits64_defined'] is False
    assert result['file_offset_bits_defined'] is True
    assert result['file_offset_bits_value'] == 32