Add tests for full screen code

Basic tests to validate different full screen functionalities. Help
prevents regressions such as #1515 where full screen simply stops
working.

Not an exhaustive test for now. Some functionalities (e.g.
multi-monitor, MacBook notch) are hard to mock up and validate in tests.
Some other functionalities like restoring window size, delayed full
screen on startup (when setting it from gvimrc) will be added later.
This commit is contained in:
Yee Cheng Chin
2024-12-28 20:12:52 -08:00
parent ea84370fcf
commit 2b136dbac1
+133 -4
View File
@@ -15,6 +15,8 @@
#import "Miscellaneous.h"
#import "MMAppController.h"
#import "MMApplication.h"
#import "MMFullScreenWindow.h"
#import "MMWindow.h"
#import "MMTextView.h"
#import "MMWindowController.h"
#import "MMVimController.h"
@@ -30,10 +32,6 @@
@end
// Test harness
@interface MMAppController (Tests)
- (NSMutableArray*)vimControllers;
@end
@implementation MMAppController (Tests)
- (NSMutableArray*)vimControllers {
return vimControllers;
@@ -50,6 +48,12 @@ static BOOL forceInLiveResize = NO;
}
@end
@implementation MMWindowController (Tests)
- (BOOL)fullScreenEnabled {
return fullScreenEnabled;
}
@end
@interface MacVimTests : XCTestCase
@end
@@ -733,4 +737,129 @@ do { \
[self waitForVimClose];
}
- (void)waitForNativeFullscreenEnter {
XCTestExpectation *expectation = [self expectationWithDescription:@"NativeFullscreenEnter"];
SEL sel = @selector(windowDidEnterFullScreen:);
Method method = class_getInstanceMethod([MMWindowController class], sel);
IMP origIMP = method_getImplementation(method);
IMP newIMP = imp_implementationWithBlock(^(id self, id notification) {
typedef void (*fn)(id,SEL,NSNotification*);
((fn)origIMP)(self, sel, notification);
[expectation fulfill];
});
method_setImplementation(method, newIMP);
[self waitForExpectations:@[expectation] timeout:10];
method_setImplementation(method, origIMP);
}
- (void)waitForNativeFullscreenExit {
XCTestExpectation *expectation = [self expectationWithDescription:@"NativeFullscreenExit"];
SEL sel = @selector(windowDidExitFullScreen:);
Method method = class_getInstanceMethod([MMWindowController class], sel);
IMP origIMP = method_getImplementation(method);
IMP newIMP = imp_implementationWithBlock(^(id self, id notification) {
typedef void (*fn)(id,SEL,NSNotification*);
((fn)origIMP)(self, sel, notification);
[expectation fulfill];
});
method_setImplementation(method, newIMP);
[self waitForExpectations:@[expectation] timeout:10];
method_setImplementation(method, origIMP);
}
/// Utility to test full screen functionality in both non-native/native full
/// screen.
- (void) fullScreenTestWithNative:(BOOL)native {
MMAppController *app = MMAppController.sharedInstance;
// Cache test defaults
NSUserDefaults *ud = NSUserDefaults.standardUserDefaults;
NSDictionary<NSString *, id> *defaults = [ud volatileDomainForName:NSArgumentDomain];
NSMutableDictionary<NSString *, id> *newDefaults = [defaults mutableCopy];
// Change native full screen setting
newDefaults[MMNativeFullScreenKey] = [NSNumber numberWithBool:native];
[ud setVolatileDomain:newDefaults forName:NSArgumentDomain];
[app openNewWindow:NewWindowClean activate:YES];
[self waitForVimOpenAndMessages];
MMWindowController *winController = app.keyVimController.windowController;
// Enter full screen and check that the states are properly changed.
[self sendStringToVim:@":set fu\n" withMods:0];
if (native) {
[self waitForNativeFullscreenEnter];
} else {
[self waitForEventHandlingAndVimProcess];
[self waitForEventHandlingAndVimProcess]; // wait one more cycle to make sure we finished the transition
}
XCTAssertTrue([winController fullScreenEnabled]);
if (native) {
XCTAssertTrue([winController.window isKindOfClass:[MMWindow class]]);
} else {
XCTAssertTrue([winController.window isKindOfClass:[MMFullScreenWindow class]]);
}
// Exit full screen
[self sendStringToVim:@":set nofu\n" withMods:0];
if (native) {
[self waitForNativeFullscreenExit];
} else {
[self waitForEventHandlingAndVimProcess];
[self waitForEventHandlingAndVimProcess]; // wait one more cycle to make sure we finished the transition
}
XCTAssertFalse([winController fullScreenEnabled]);
XCTAssertTrue([winController.window isKindOfClass:[MMWindow class]]);
// Enter full screen again
[self sendStringToVim:@":set fu\n" withMods:0];
if (native) {
[self waitForNativeFullscreenEnter];
} else {
[self waitForEventHandlingAndVimProcess];
[self waitForEventHandlingAndVimProcess]; // wait one more cycle to make sure we finished the transition
}
XCTAssertTrue([winController fullScreenEnabled]);
// Test that resizing the vim view does not work when in full screen as we fix the window size instead
MMTextView *textView = [[[[app keyVimController] windowController] vimView] textView];
const int fuRows = textView.maxRows;
const int fuCols = textView.maxColumns;
XCTAssertNotEqual(10, fuRows); // just some basic assumptions as full screen should have more rows/cols than this
XCTAssertNotEqual(30, fuCols);
[self sendStringToVim:@":set lines=10\n" withMods:0];
[self sendStringToVim:@":set columns=30\n" withMods:0];
[self waitForEventHandlingAndVimProcess];
[self waitForEventHandlingAndVimProcess]; // need to wait twice to allow full screen to force it back
XCTAssertEqual(fuRows, textView.maxRows);
XCTAssertEqual(fuCols, textView.maxColumns);
// Clean up
[[app keyVimController] sendMessage:VimShouldCloseMsgID data:nil];
[self waitForVimClose];
XCTAssertEqual(0, [app vimControllers].count);
// Restore settings to test defaults
[ud setVolatileDomain:defaults forName:NSArgumentDomain];
}
- (void) testFullScreenNonNative {
[self fullScreenTestWithNative:NO];
}
- (void) testFullScreenNative {
[self fullScreenTestWithNative:YES];
}
@end