mirror of https://github.com/python/cpython
158 lines
5.1 KiB
Objective-C
158 lines
5.1 KiB
Objective-C
#import <XCTest/XCTest.h>
|
|
#import <Python/Python.h>
|
|
|
|
@interface iOSTestbedTests : XCTestCase
|
|
|
|
@end
|
|
|
|
@implementation iOSTestbedTests
|
|
|
|
|
|
- (void)testPython {
|
|
const char **argv;
|
|
int exit_code;
|
|
int failed;
|
|
PyStatus status;
|
|
PyPreConfig preconfig;
|
|
PyConfig config;
|
|
PyObject *sys_module;
|
|
PyObject *sys_path_attr;
|
|
NSArray *test_args;
|
|
NSString *python_home;
|
|
NSString *path;
|
|
wchar_t *wtmp_str;
|
|
|
|
NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
|
|
|
|
// Disable all color, as the Xcode log can't display color
|
|
setenv("NO_COLOR", "1", true);
|
|
|
|
// Arguments to pass into the test suite runner.
|
|
// argv[0] must identify the process; any subsequent arg
|
|
// will be handled as if it were an argument to `python -m test`
|
|
test_args = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"TestArgs"];
|
|
if (test_args == NULL) {
|
|
NSLog(@"Unable to identify test arguments.");
|
|
}
|
|
argv = malloc(sizeof(char *) * ([test_args count] + 1));
|
|
argv[0] = "iOSTestbed";
|
|
for (int i = 1; i < [test_args count]; i++) {
|
|
argv[i] = [[test_args objectAtIndex:i] UTF8String];
|
|
}
|
|
NSLog(@"Test command: %@", test_args);
|
|
|
|
// Generate an isolated Python configuration.
|
|
NSLog(@"Configuring isolated Python...");
|
|
PyPreConfig_InitIsolatedConfig(&preconfig);
|
|
PyConfig_InitIsolatedConfig(&config);
|
|
|
|
// Configure the Python interpreter:
|
|
// Enforce UTF-8 encoding for stderr, stdout, file-system encoding and locale.
|
|
// See https://docs.python.org/3/library/os.html#python-utf-8-mode.
|
|
preconfig.utf8_mode = 1;
|
|
// Don't buffer stdio. We want output to appears in the log immediately
|
|
config.buffered_stdio = 0;
|
|
// Don't write bytecode; we can't modify the app bundle
|
|
// after it has been signed.
|
|
config.write_bytecode = 0;
|
|
// Ensure that signal handlers are installed
|
|
config.install_signal_handlers = 1;
|
|
// Run the test module.
|
|
config.run_module = Py_DecodeLocale([[test_args objectAtIndex:0] UTF8String], NULL);
|
|
// For debugging - enable verbose mode.
|
|
// config.verbose = 1;
|
|
|
|
NSLog(@"Pre-initializing Python runtime...");
|
|
status = Py_PreInitialize(&preconfig);
|
|
if (PyStatus_Exception(status)) {
|
|
XCTFail(@"Unable to pre-initialize Python interpreter: %s", status.err_msg);
|
|
PyConfig_Clear(&config);
|
|
return;
|
|
}
|
|
|
|
// Set the home for the Python interpreter
|
|
python_home = [NSString stringWithFormat:@"%@/python", resourcePath, nil];
|
|
NSLog(@"PythonHome: %@", python_home);
|
|
wtmp_str = Py_DecodeLocale([python_home UTF8String], NULL);
|
|
status = PyConfig_SetString(&config, &config.home, wtmp_str);
|
|
if (PyStatus_Exception(status)) {
|
|
XCTFail(@"Unable to set PYTHONHOME: %s", status.err_msg);
|
|
PyConfig_Clear(&config);
|
|
return;
|
|
}
|
|
PyMem_RawFree(wtmp_str);
|
|
|
|
// Read the site config
|
|
status = PyConfig_Read(&config);
|
|
if (PyStatus_Exception(status)) {
|
|
XCTFail(@"Unable to read site config: %s", status.err_msg);
|
|
PyConfig_Clear(&config);
|
|
return;
|
|
}
|
|
|
|
NSLog(@"Configure argc/argv...");
|
|
status = PyConfig_SetBytesArgv(&config, [test_args count], (char**) argv);
|
|
if (PyStatus_Exception(status)) {
|
|
XCTFail(@"Unable to configure argc/argv: %s", status.err_msg);
|
|
PyConfig_Clear(&config);
|
|
return;
|
|
}
|
|
|
|
NSLog(@"Initializing Python runtime...");
|
|
status = Py_InitializeFromConfig(&config);
|
|
if (PyStatus_Exception(status)) {
|
|
XCTFail(@"Unable to initialize Python interpreter: %s", status.err_msg);
|
|
PyConfig_Clear(&config);
|
|
return;
|
|
}
|
|
|
|
sys_module = PyImport_ImportModule("sys");
|
|
if (sys_module == NULL) {
|
|
XCTFail(@"Could not import sys module");
|
|
return;
|
|
}
|
|
|
|
sys_path_attr = PyObject_GetAttrString(sys_module, "path");
|
|
if (sys_path_attr == NULL) {
|
|
XCTFail(@"Could not access sys.path");
|
|
return;
|
|
}
|
|
|
|
// Add the app packages path
|
|
path = [NSString stringWithFormat:@"%@/app_packages", resourcePath, nil];
|
|
NSLog(@"App packages path: %@", path);
|
|
wtmp_str = Py_DecodeLocale([path UTF8String], NULL);
|
|
failed = PyList_Insert(sys_path_attr, 0, PyUnicode_FromString([path UTF8String]));
|
|
if (failed) {
|
|
XCTFail(@"Unable to add app packages to sys.path");
|
|
return;
|
|
}
|
|
PyMem_RawFree(wtmp_str);
|
|
|
|
path = [NSString stringWithFormat:@"%@/app", resourcePath, nil];
|
|
NSLog(@"App path: %@", path);
|
|
wtmp_str = Py_DecodeLocale([path UTF8String], NULL);
|
|
failed = PyList_Insert(sys_path_attr, 0, PyUnicode_FromString([path UTF8String]));
|
|
if (failed) {
|
|
XCTFail(@"Unable to add app to sys.path");
|
|
return;
|
|
}
|
|
PyMem_RawFree(wtmp_str);
|
|
|
|
// Ensure the working directory is the app folder.
|
|
chdir([path UTF8String]);
|
|
|
|
// Start the test suite. Print a separator to differentiate Python startup logs from app logs
|
|
NSLog(@"---------------------------------------------------------------------------");
|
|
|
|
exit_code = Py_RunMain();
|
|
XCTAssertEqual(exit_code, 0, @"Test suite did not pass");
|
|
|
|
NSLog(@"---------------------------------------------------------------------------");
|
|
|
|
Py_Finalize();
|
|
}
|
|
|
|
|
|
@end
|