1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4"""test_broken_cmakelists
5----------------------------------
6
7Tries to build the `fail-with-*-cmakelists` sample projects.  Ensures that the
8attempt fails with a SystemExit exception that has an SKBuildError exception as
9its value.
10"""
11
12import pytest
13
14from subprocess import (check_output, CalledProcessError)
15
16from skbuild.constants import CMAKE_DEFAULT_EXECUTABLE
17from skbuild.exceptions import SKBuildError
18from skbuild.platform_specifics import CMakeGenerator, get_platform
19from skbuild.utils import push_dir
20
21from . import project_setup_py_test
22from . import push_env
23
24
25def test_cmakelists_with_fatalerror_fails(capfd):
26
27    with push_dir():
28
29        @project_setup_py_test("fail-with-fatal-error-cmakelists", ["build"], disable_languages_test=True)
30        def should_fail():
31            pass
32
33        failed = False
34        message = ""
35        try:
36            should_fail()
37        except SystemExit as e:
38            failed = isinstance(e.code, SKBuildError)
39            message = str(e)
40
41    assert failed
42
43    _, err = capfd.readouterr()
44    assert "Invalid CMakeLists.txt" in err
45    assert "An error occurred while configuring with CMake." in message
46
47
48def test_cmakelists_with_syntaxerror_fails(capfd):
49
50    with push_dir():
51
52        @project_setup_py_test("fail-with-syntax-error-cmakelists", ["build"], disable_languages_test=True)
53        def should_fail():
54            pass
55
56        failed = False
57        message = ""
58        try:
59            should_fail()
60        except SystemExit as e:
61            failed = isinstance(e.code, SKBuildError)
62            message = str(e)
63
64    assert failed
65
66    _, err = capfd.readouterr()
67    assert "Parse error.  Function missing ending \")\"" in err
68    assert "An error occurred while configuring with CMake." in message
69
70
71def test_hello_with_compileerror_fails(capfd):
72
73    with push_dir():
74
75        @project_setup_py_test("fail-hello-with-compile-error", ["build"])
76        def should_fail():
77            pass
78
79        failed = False
80        message = ""
81        try:
82            should_fail()
83        except SystemExit as e:
84            failed = isinstance(e.code, SKBuildError)
85            message = str(e)
86
87    assert failed
88
89    out, err = capfd.readouterr()
90    assert "_hello.cxx" in out or "_hello.cxx" in err
91    assert "An error occurred while building with CMake." in message
92
93
94@pytest.mark.parametrize("exception", [CalledProcessError, OSError])
95def test_invalid_cmake(exception, mocker):
96
97    exceptions = {
98        OSError: OSError('Unknown error'),
99        CalledProcessError: CalledProcessError([CMAKE_DEFAULT_EXECUTABLE, '--version'], 1)
100    }
101
102    check_output_original = check_output
103
104    def check_output_mock(*args, **kwargs):
105        if args[0] == [CMAKE_DEFAULT_EXECUTABLE, '--version']:
106            raise exceptions[exception]
107        return check_output_original(*args, **kwargs)
108
109    mocker.patch('skbuild.cmaker.subprocess.check_output',
110                 new=check_output_mock)
111
112    with push_dir():
113
114        @project_setup_py_test("hello-no-language", ["build"], disable_languages_test=True)
115        def should_fail():
116            pass
117
118        failed = False
119        message = ""
120        try:
121            should_fail()
122        except SystemExit as e:
123            failed = isinstance(e.code, SKBuildError)
124            message = str(e)
125
126    assert failed
127    assert "Problem with the CMake installation, aborting build." in message
128
129
130def test_first_invalid_generator(mocker, capfd):
131    platform = get_platform()
132    default_generators = [CMakeGenerator('Invalid')]
133    default_generators.extend(platform.default_generators)
134    mocker.patch.object(type(platform), 'default_generators',
135                        new_callable=mocker.PropertyMock,
136                        return_value=default_generators)
137
138    mocker.patch('skbuild.cmaker.get_platform', return_value=platform)
139
140    with push_dir(), push_env(CMAKE_GENERATOR=None):
141        @project_setup_py_test("hello-no-language", ["build"])
142        def run_build():
143            pass
144
145        run_build()
146
147    _, err = capfd.readouterr()
148    assert "CMake Error: Could not create named generator Invalid" in err
149
150
151def test_invalid_generator(mocker, capfd):
152    platform = get_platform()
153    mocker.patch.object(type(platform), 'default_generators',
154                        new_callable=mocker.PropertyMock,
155                        return_value=[CMakeGenerator('Invalid')])
156    mocker.patch('skbuild.cmaker.get_platform', return_value=platform)
157
158    with push_dir(), push_env(CMAKE_GENERATOR=None):
159        @project_setup_py_test("hello-no-language", ["build"])
160        def should_fail():
161            pass
162
163        failed = False
164        message = ""
165        try:
166            should_fail()
167        except SystemExit as e:
168            failed = isinstance(e.code, SKBuildError)
169            message = str(e)
170
171    _, err = capfd.readouterr()
172
173    assert "CMake Error: Could not create named generator Invalid" in err
174    assert failed
175    assert "scikit-build could not get a working generator for your system." \
176           " Aborting build." in message
177