Skip to content

Commit 180aab3

Browse files
committed
Update to version 2.
The signing is now automatically controlled and includes provisioning profiles on both iOS and macOS platforms (due to the addition of the iCloud capability). The test description strings that appear in the picker are now sourced from the test library itself, so no code editing has to happen on the XCode side and it's a lot easier to keep the descriptions in sync with the test ops themselves. Documentation has been updated.
1 parent 7c6d293 commit 180aab3

File tree

7 files changed

+76
-41
lines changed

7 files changed

+76
-41
lines changed

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
This project is a resource for developers who want to build iOS or macOS apps that make use of Rust libraries.
44

5-
The `rust-test-harness` Xcode project in this repo provides an XCode-based application that can be used to invoke a Rust-built static library. It expects the crate being tested to provide a static library with a single `extern C` entrypoint with the signature `void test(int op)` (on the Rust side, that’s `extern "C" fn test(op i32)` with name mangling turned off). When the iOS build target is run in the simulator (or on an iOS device), or whenb the macOS build target is run on a Mac, the test harness puts up a screen with a picker for which test you want to run, and then it passes the index of that choice as the argument to the `test` entry.
5+
The `rust-test-harness` Xcode project in this repo provides an XCode-based application that can be used to invoke a Rust-built static library. It expects the crate being tested to provide a static library with a two `extern C` entrypoint:
66

7-
If the test runs without panicing, you get an alert on the iOS side that says to check the logs for details. Anything you print to stdout on the Rust side will be in the log.
7+
* a `test` entrypoint with the signature `void test(int op)` (on the Rust side, that’s `extern "C" fn test(op i32)` with name mangling turned off). When the iOS build target is run in the simulator (or on an iOS device), or when the macOS build target is run on a Mac, the test harness puts up a screen with a picker for which test you want to run, below which is a “Run test” button.
8+
* a `choices` entrypoint with the signature `const char* choices()` (on the Rust side, that’s `extern "C" fn choices() -> const std::ffi::c_char`). This function is called once when the iOS app is first started, and should return descriptions of the tests (in choice order), one per line, separated by newlines (leading and trailing spaces and blank lines are ignored). So, for example `“test0\ntest1\n”` would show “test0” as the description of test operation 0, and “test1” as the description of test operation 1.
89

9-
The test harness can be used on your own crates simply by cloning it locally and creating an appropriate `test-spec.sh` file at the top level of the project which declares where your crate is and how to build the test library. You can copy the `test-spec.sample.sh` file to `test-spec.sh` in order to get started. Detailed instructions are in the next section.
10+
Whenever you hit the “Run test” button in the app, a spinner replaces the button while a background task is executed making the call `test(op)` where `op` is the index of the description the user has chosen in the picker. Once the spinner disappears and the button comes back, you can run the next test.
11+
12+
The test harness can be used on your own crates by cloning it locally and creating an appropriate `test-spec.sh` file at the top level of the project which declares where your crate is and how to build the test library. You can copy the `test-spec.sample.sh` file to `test-spec.sh` in order to get started. Detailed instructions are in the next section.
1013

1114
**PLEASE NOTE**: You will need your own Apple developer account in order to build and run this project, because both the iOS and macOS targets use provisioning profiles. You will have to change those provisioning profiles to ones that you own.
1215

@@ -26,14 +29,12 @@ If both `CRATE_PACKAGE` and `CRATE_EXAMPLE` are specified, the build will specif
2629

2730
This test harness can be used to test both debug and release builds of your crate. Running the test harness in the Debug configuration will do a debug build of your library, and similarly for Release.
2831

29-
The XCode target of your build (e.g., a macOS device, an iOS device or an iOS device simulator) will be used to pick an appropriate target platform for your rust library build. You must have installed the appropriate target support on your machine.
32+
The XCode target of your build (e.g., a macOS device, an iOS device or an iOS device simulator) will be used to pick an appropriate target platform for your Rust library build. You must have installed the appropriate target support on your machine.
3033

3134
(N.B. This test harness assumes you have done a standard install of Rust using `rustup` and sets the `PATH` variable based on that when building your test library.)
3235

3336
For example: The `test-spec.sample.sh` file that comes with this project assumes that the directory containing the `ios-test-harness.xcodeproj` bundle (that is, the top level of this repository) is adjacent to the directory containing the crate being tested (called `keyring-rs`), and that the test library is an example in that crate.
3437

35-
Before running the test harness, you will want to edit the code in `ContentView.swift` (in the `test-runner` directory) to have the correct descriptions (and correct number) of test opcodes for your library. A future project of mine will be to load the opcodes and descriptions from the static library that you test.
36-
3738
## License
3839

3940
Licensed under either of
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>com.apple.developer.icloud-container-identifiers</key>
6+
<array/>
7+
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
8+
<string>$(TeamIdentifierPrefix)$(CFBundleIdentifier)</string>
9+
</dict>
10+
</plist>

macos-test-harness/macos_test_harness.entitlements

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
33
<plist version="1.0">
44
<dict>
5+
<key>com.apple.developer.icloud-container-identifiers</key>
6+
<array/>
7+
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
8+
<string>$(TeamIdentifierPrefix)$(CFBundleIdentifier)</string>
59
<key>com.apple.security.app-sandbox</key>
610
<true/>
711
<key>com.apple.security.files.user-selected.read-only</key>

rust-test-harness.xcodeproj/project.pbxproj

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
377969C327A6826300F0EF3C /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; };
4040
37C7AC0127B8E179004C69C2 /* test-spec.sample.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "test-spec.sample.sh"; sourceTree = "<group>"; };
4141
37C7AC0227BA095B004C69C2 /* test-spec.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "test-spec.sh"; sourceTree = "<group>"; };
42+
37E6FB622E43C59A00D77CA6 /* ios-test-harness.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "ios-test-harness.entitlements"; sourceTree = "<group>"; };
4243
/* End PBXFileReference section */
4344

4445
/* Begin PBXFileSystemSynchronizedRootGroup section */
@@ -92,6 +93,7 @@
9293
3779698D27A6749700F0EF3C /* ios-test-harness */ = {
9394
isa = PBXGroup;
9495
children = (
96+
37E6FB622E43C59A00D77CA6 /* ios-test-harness.entitlements */,
9597
3779698E27A6749700F0EF3C /* ios_test_harnessApp.swift */,
9698
3779699227A6749A00F0EF3C /* Assets.xcassets */,
9799
3779699427A6749A00F0EF3C /* Preview Content */,
@@ -311,12 +313,11 @@
311313
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
312314
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
313315
CODE_SIGN_ENTITLEMENTS = "macos-test-harness/macos_test_harness.entitlements";
314-
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Mac Developer";
315-
CODE_SIGN_STYLE = Manual;
316+
CODE_SIGN_IDENTITY = "Apple Development";
317+
CODE_SIGN_STYLE = Automatic;
316318
COMBINE_HIDPI_IMAGES = YES;
317-
CURRENT_PROJECT_VERSION = 1;
318-
DEVELOPMENT_TEAM = "";
319-
"DEVELOPMENT_TEAM[sdk=macosx*]" = 85H73V9R3F;
319+
CURRENT_PROJECT_VERSION = 2.0.1;
320+
DEVELOPMENT_TEAM = 85H73V9R3F;
320321
ENABLE_HARDENED_RUNTIME = YES;
321322
ENABLE_PREVIEWS = YES;
322323
ENABLE_USER_SCRIPT_SANDBOXING = NO;
@@ -334,11 +335,10 @@
334335
"LIBRARY_SEARCH_PATHS[arch=*]" = "$(DERIVED_FILES_DIR)";
335336
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
336337
MACOSX_DEPLOYMENT_TARGET = 15.5;
337-
MARKETING_VERSION = 1.0;
338+
MARKETING_VERSION = 2.0;
338339
PRODUCT_BUNDLE_IDENTIFIER = "com.brotsky.rust-test-harness";
339340
PRODUCT_NAME = "$(TARGET_NAME)";
340341
PROVISIONING_PROFILE_SPECIFIER = "";
341-
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "Rust Test Harness MacOS Development";
342342
REGISTER_APP_GROUPS = YES;
343343
SDKROOT = macosx;
344344
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
@@ -356,12 +356,11 @@
356356
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
357357
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
358358
CODE_SIGN_ENTITLEMENTS = "macos-test-harness/macos_test_harness.entitlements";
359-
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Mac Developer";
360-
CODE_SIGN_STYLE = Manual;
359+
CODE_SIGN_IDENTITY = "Apple Development";
360+
CODE_SIGN_STYLE = Automatic;
361361
COMBINE_HIDPI_IMAGES = YES;
362-
CURRENT_PROJECT_VERSION = 1;
363-
DEVELOPMENT_TEAM = "";
364-
"DEVELOPMENT_TEAM[sdk=macosx*]" = 85H73V9R3F;
362+
CURRENT_PROJECT_VERSION = 2.0.1;
363+
DEVELOPMENT_TEAM = 85H73V9R3F;
365364
ENABLE_HARDENED_RUNTIME = YES;
366365
ENABLE_PREVIEWS = YES;
367366
ENABLE_USER_SCRIPT_SANDBOXING = NO;
@@ -379,11 +378,10 @@
379378
"LIBRARY_SEARCH_PATHS[arch=*]" = "$(DERIVED_FILES_DIR)";
380379
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
381380
MACOSX_DEPLOYMENT_TARGET = 15.5;
382-
MARKETING_VERSION = 1.0;
381+
MARKETING_VERSION = 2.0;
383382
PRODUCT_BUNDLE_IDENTIFIER = "com.brotsky.rust-test-harness";
384383
PRODUCT_NAME = "$(TARGET_NAME)";
385384
PROVISIONING_PROFILE_SPECIFIER = "";
386-
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "Rust Test Harness MacOS Development";
387385
REGISTER_APP_GROUPS = YES;
388386
SDKROOT = macosx;
389387
SWIFT_EMIT_LOC_STRINGS = YES;
@@ -515,8 +513,9 @@
515513
buildSettings = {
516514
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
517515
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
516+
CODE_SIGN_ENTITLEMENTS = "ios-test-harness/ios-test-harness.entitlements";
518517
CODE_SIGN_STYLE = Automatic;
519-
CURRENT_PROJECT_VERSION = 1;
518+
CURRENT_PROJECT_VERSION = 2.0.1;
520519
DEVELOPMENT_ASSET_PATHS = "\"ios-test-harness/Preview Content\"";
521520
DEVELOPMENT_TEAM = 85H73V9R3F;
522521
ENABLE_PREVIEWS = YES;
@@ -534,7 +533,7 @@
534533
LIBRARY_SEARCH_PATHS = "$(DERIVED_FILES_DIR)";
535534
"LIBRARY_SEARCH_PATHS[arch=*]" = "$(DERIVED_FILES_DIR)";
536535
LINKER_DISPLAYS_MANGLED_NAMES = NO;
537-
MARKETING_VERSION = 1.0;
536+
MARKETING_VERSION = 2.0;
538537
OTHER_LDFLAGS = "";
539538
PRODUCT_BUNDLE_IDENTIFIER = "com.brotsky.rust-test-harness";
540539
PRODUCT_NAME = "iOS Test Harness";
@@ -550,8 +549,9 @@
550549
buildSettings = {
551550
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
552551
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
552+
CODE_SIGN_ENTITLEMENTS = "ios-test-harness/ios-test-harness.entitlements";
553553
CODE_SIGN_STYLE = Automatic;
554-
CURRENT_PROJECT_VERSION = 1;
554+
CURRENT_PROJECT_VERSION = 2.0.1;
555555
DEVELOPMENT_ASSET_PATHS = "\"ios-test-harness/Preview Content\"";
556556
DEVELOPMENT_TEAM = 85H73V9R3F;
557557
ENABLE_PREVIEWS = YES;
@@ -569,7 +569,7 @@
569569
LIBRARY_SEARCH_PATHS = "$(DERIVED_FILES_DIR)";
570570
"LIBRARY_SEARCH_PATHS[arch=*]" = "$(DERIVED_FILES_DIR)";
571571
LINKER_DISPLAYS_MANGLED_NAMES = NO;
572-
MARKETING_VERSION = 1.0;
572+
MARKETING_VERSION = 2.0;
573573
OTHER_LDFLAGS = "";
574574
PRODUCT_BUNDLE_IDENTIFIER = "com.brotsky.rust-test-harness";
575575
PRODUCT_NAME = "iOS Test Harness";

test-runner/ContentView.swift

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,47 @@ struct TestChoice: Identifiable {
1212
let description: String
1313
}
1414

15-
let testOps = [
16-
TestChoice(id: 0, description: "Create entry with no user presence required"),
17-
TestChoice(id: 1, description: "Create entry with user presence required"),
18-
TestChoice(id: 2, description: "Set an existing entry"),
19-
TestChoice(id: 3, description: "Read an existing entry"),
20-
TestChoice(id: 4, description: "Delete an existing entry"),
21-
];
15+
func createTestOps() -> [TestChoice] {
16+
let choiceString = TestRunner.getTestChoices()
17+
let choices = choiceString.split(separator: "\n", omittingEmptySubsequences: true)
18+
var result: [TestChoice] = []
19+
for i in 0..<choices.count {
20+
let choice = String(choices[i]).trimmingCharacters(in: .whitespaces)
21+
if choice.isEmpty { continue }
22+
result.append(TestChoice(id: Int32(i), description: String(choices[i]).trimmingCharacters(in: .whitespaces)))
23+
}
24+
return result
25+
}
2226

2327
struct ContentView: View {
24-
@State var showAlert = false;
25-
@State var testOpIndex: Int32 = 0;
28+
@State var testOpIndex: Int32 = 0
29+
@State var testInProgress: Bool = false
30+
31+
let testOps = createTestOps()
2632

2733
var body: some View {
2834
Picker("Choose operation", selection: $testOpIndex) {
2935
ForEach(testOps) {
3036
Text($0.description).tag($0.id)
3137
}
32-
}
33-
Button("Run Test") {
34-
TestRunner.runTest(testOpIndex)
35-
showAlert = true
3638
}.padding(10)
37-
.alert(isPresented: $showAlert) {
38-
Alert(title: Text("Test Result"),
39-
message: Text("No crash! See the log for details."))
40-
}
39+
if testInProgress {
40+
ProgressView("Test in progress...").padding(10)
41+
} else {
42+
Button("Run Test") {
43+
runTest()
44+
}.padding(10)
45+
}
4146
}
47+
48+
func runTest() {
49+
testInProgress = true
50+
let task = DispatchWorkItem {
51+
TestRunner.runTest(self.testOpIndex)
52+
self.testInProgress = false
53+
}
54+
task.perform()
55+
}
4256
}
4357

4458
struct ContentView_Previews: PreviewProvider {

test-runner/TestRunner.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,8 @@ class TestRunner {
99
static func runTest(_ op: Int32) {
1010
test(op)
1111
}
12+
13+
static func getTestChoices() -> String {
14+
return String(cString: choices())
15+
}
1216
}

test-runner/test.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@
88

99
extern void test(int op);
1010

11+
extern const char* choices();
12+
1113
#endif /* test_h */

0 commit comments

Comments
 (0)