Skip to content

Commit fdf418e

Browse files
committed
up
1 parent 1b1db6a commit fdf418e

1 file changed

Lines changed: 49 additions & 49 deletions

File tree

extension/apple/ExecuTorch/__tests__/ObjC/ModuleTestObjC.m

Lines changed: 49 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -11,55 +11,6 @@
1111
#import <ExecuTorch/ExecuTorch.h>
1212

1313
@interface ModuleTestObjC : XCTestCase
14-
// Covers -[ExecuTorchModule loadMethod:options:error:] and locks the
15-
// "load_method consumes the borrow synchronously and does not cache it"
16-
// invariant that the no-retain decision in the wrapper rests on.
17-
// See the citation on ExecuTorchModule.mm's loadMethod:options:error:
18-
// (module.cpp#L353-L409). If a future refactor caches `backend_options`
19-
// on the Module, this test fails (the weak reference stays non-nil).
20-
- (void)testLoadMethodWithOptionsDoesNotRetainOptions {
21-
NSString *modelPath = [self requireFixture:@"add_coreml" ofType:@"pte"];
22-
if (!modelPath) return;
23-
NSError *error = nil;
24-
ExecuTorchModule *module = [[ExecuTorchModule alloc] initWithFilePath:modelPath];
25-
26-
__weak ExecuTorchBackendOptionsMap *weakOptions = nil;
27-
@autoreleasepool {
28-
ExecuTorchBackendOptionsMap *options = [ExecuTorchBackendOptionsMap mapWithOptions:@{
29-
@"CoreMLBackend": @[
30-
[ExecuTorchBackendOption optionWithKey:@"compute_unit" stringValue:@"cpu_and_gpu"],
31-
],
32-
} error:&error];
33-
XCTAssertNotNil(options, @"%@", error);
34-
weakOptions = options;
35-
XCTAssertTrue([module loadMethod:@"forward" options:options error:&error],
36-
@"%@", error);
37-
XCTAssertTrue([module isMethodLoaded:@"forward"]);
38-
}
39-
// The local + any autoreleased refs have drained. If loadMethod:options:
40-
// silently retained the map, weakOptions would still be live here.
41-
XCTAssertNil(weakOptions,
42-
@"loadMethod:options: must not retain the map (load_method consumes "
43-
@"it synchronously). See module.cpp load_method borrow contract.");
44-
45-
// The loaded method must still run — it reads from _module->methods_
46-
// (populated during loadMethod:options:), not from the options map.
47-
ExecuTorchTensor *one =
48-
[[ExecuTorchTensor alloc] initWithScalars:@[@1.0f] dataType:ExecuTorchDataTypeFloat];
49-
NSArray<ExecuTorchValue *> *outputs =
50-
[module forwardWithTensors:@[one, one] error:&error];
51-
XCTAssertNotNil(outputs, @"%@", error);
52-
53-
__block float result = NAN;
54-
[outputs.firstObject.tensorValue
55-
bytesWithHandler:^(const void *bytes, NSInteger count, ExecuTorchDataType dt) {
56-
if (dt == ExecuTorchDataTypeFloat && count >= 1) {
57-
result = ((const float *)bytes)[0];
58-
}
59-
}];
60-
XCTAssertEqual(result, 2.0f);
61-
}
62-
6314
@end
6415

6516
@implementation ModuleTestObjC
@@ -198,4 +149,53 @@ - (void)testBackendOptionsMapReusedAcrossModules {
198149
}
199150
}
200151

152+
// Covers -[ExecuTorchModule loadMethod:options:error:] and locks the
153+
// "load_method consumes the borrow synchronously and does not cache it"
154+
// invariant that the no-retain decision in the wrapper rests on.
155+
// See the citation on ExecuTorchModule.mm's loadMethod:options:error:
156+
// (module.cpp#L353-L409). If a future refactor caches `backend_options`
157+
// on the Module, this test fails (the weak reference stays non-nil).
158+
- (void)testLoadMethodWithOptionsDoesNotRetainOptions {
159+
NSString *modelPath = [self requireFixture:@"add_coreml" ofType:@"pte"];
160+
if (!modelPath) return;
161+
NSError *error = nil;
162+
ExecuTorchModule *module = [[ExecuTorchModule alloc] initWithFilePath:modelPath];
163+
164+
__weak ExecuTorchBackendOptionsMap *weakOptions = nil;
165+
@autoreleasepool {
166+
ExecuTorchBackendOptionsMap *options = [ExecuTorchBackendOptionsMap mapWithOptions:@{
167+
@"CoreMLBackend": @[
168+
[ExecuTorchBackendOption optionWithKey:@"compute_unit" stringValue:@"cpu_and_gpu"],
169+
],
170+
} error:&error];
171+
XCTAssertNotNil(options, @"%@", error);
172+
weakOptions = options;
173+
XCTAssertTrue([module loadMethod:@"forward" options:options error:&error],
174+
@"%@", error);
175+
XCTAssertTrue([module isMethodLoaded:@"forward"]);
176+
}
177+
// The local + any autoreleased refs have drained. If loadMethod:options:
178+
// silently retained the map, weakOptions would still be live here.
179+
XCTAssertNil(weakOptions,
180+
@"loadMethod:options: must not retain the map (load_method consumes "
181+
@"it synchronously). See module.cpp load_method borrow contract.");
182+
183+
// The loaded method must still run — it reads from _module->methods_
184+
// (populated during loadMethod:options:), not from the options map.
185+
ExecuTorchTensor *one =
186+
[[ExecuTorchTensor alloc] initWithScalars:@[@1.0f] dataType:ExecuTorchDataTypeFloat];
187+
NSArray<ExecuTorchValue *> *outputs =
188+
[module forwardWithTensors:@[one, one] error:&error];
189+
XCTAssertNotNil(outputs, @"%@", error);
190+
191+
__block float result = NAN;
192+
[outputs.firstObject.tensorValue
193+
bytesWithHandler:^(const void *bytes, NSInteger count, ExecuTorchDataType dt) {
194+
if (dt == ExecuTorchDataTypeFloat && count >= 1) {
195+
result = ((const float *)bytes)[0];
196+
}
197+
}];
198+
XCTAssertEqual(result, 2.0f);
199+
}
200+
201201
@end

0 commit comments

Comments
 (0)