Initial release
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <objc/message.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#import "../../lib/cstring.h"
|
||||
#import "../../lib/vstguiinit.h"
|
||||
#import "unittests.h"
|
||||
|
||||
#import <functional>
|
||||
#import <string>
|
||||
#import <unordered_map>
|
||||
#import <vector>
|
||||
|
||||
using namespace VSTGUI::UnitTest;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void setupFunc (id self, SEL _cmd)
|
||||
{
|
||||
auto cls = [self class];
|
||||
std::string clsName (class_getName (cls) + 7);
|
||||
auto testSuite = UnitTestRegistry::instance ().find (clsName);
|
||||
assert (testSuite);
|
||||
auto ivar = class_getInstanceVariable ([self class], "_testSuite");
|
||||
object_setIvar (self, ivar, reinterpret_cast<id> (testSuite));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void testFunc (id self, SEL _cmd)
|
||||
{
|
||||
auto ivar = class_getInstanceVariable ([self class], "_testSuite");
|
||||
auto testSuite = reinterpret_cast<TestSuite*> (object_getIvar (self, ivar));
|
||||
auto name = std::string (sel_getName (_cmd) + 4);
|
||||
auto it = std::find_if (testSuite->begin (), testSuite->end (),
|
||||
[&] (auto& pair) { return pair.first == name; });
|
||||
assert (it != testSuite->end ());
|
||||
|
||||
struct TestContext : Context
|
||||
{
|
||||
TestContext (TestSuite& suite) : suite (suite) {}
|
||||
void printRaw (const char* str) override { text += str; }
|
||||
std::any& storage () override { return suite.getStorage (); }
|
||||
TestSuite& suite;
|
||||
std::string text;
|
||||
} context (*testSuite);
|
||||
|
||||
size_t assertLineNo = 0;
|
||||
std::string assertFilePath;
|
||||
|
||||
bool result = true;
|
||||
|
||||
try
|
||||
{
|
||||
if (auto setup = testSuite->setup ())
|
||||
setup (&context);
|
||||
|
||||
try
|
||||
{
|
||||
it->second (&context);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (auto teardown = testSuite->teardown ())
|
||||
teardown (&context);
|
||||
throw;
|
||||
}
|
||||
|
||||
if (auto teardown = testSuite->teardown ())
|
||||
teardown (&context);
|
||||
}
|
||||
catch (const error& exc)
|
||||
{
|
||||
result = false;
|
||||
context.print ("%s", exc.what () ? exc.what () : "unknown");
|
||||
assertLineNo = exc.lineNo;
|
||||
assertFilePath = exc.filePath;
|
||||
}
|
||||
catch (const std::logic_error& exc)
|
||||
{
|
||||
result = false;
|
||||
context.print ("%s", exc.what () ? exc.what () : "unknown");
|
||||
}
|
||||
catch (const std::exception& exc)
|
||||
{
|
||||
result = false;
|
||||
context.print ("Exception: %s", exc.what () ? exc.what () : "unknown");
|
||||
}
|
||||
if (!result)
|
||||
{
|
||||
#ifdef MAC_OS_VERSION_11_0
|
||||
auto sourceCodeLocation = [[[XCTSourceCodeLocation alloc]
|
||||
initWithFilePath:[NSString stringWithUTF8String:assertFilePath.data ()]
|
||||
lineNumber:assertLineNo] autorelease];
|
||||
auto sourceCodeContext =
|
||||
[[[XCTSourceCodeContext alloc] initWithLocation:sourceCodeLocation] autorelease];
|
||||
auto issue =
|
||||
[[[XCTIssue alloc] initWithType:XCTIssueTypeAssertionFailure
|
||||
compactDescription:[NSString stringWithUTF8String:context.text.data ()]
|
||||
detailedDescription:nullptr
|
||||
sourceCodeContext:sourceCodeContext
|
||||
associatedError:nullptr
|
||||
attachments:@[]] autorelease];
|
||||
|
||||
[self recordIssue:issue];
|
||||
#else
|
||||
|
||||
[self recordFailureWithDescription:[NSString stringWithUTF8String:context.text.data ()]
|
||||
inFile:[NSString stringWithUTF8String:assertFilePath.data ()]
|
||||
atLine:assertLineNo
|
||||
expected:NO];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
@interface VSTGUITestCaseFactory : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation VSTGUITestCaseFactory
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
+ (void)initialize
|
||||
{
|
||||
VSTGUI::setAssertionHandler (
|
||||
[] (const char* file, const char* line, const char* condition, const char* desc) {
|
||||
size_t lineNo = 0;
|
||||
if (line)
|
||||
{
|
||||
if (auto l = VSTGUI::UTF8StringView (line).toNumber<size_t> ())
|
||||
lineNo = *l;
|
||||
}
|
||||
std::string text;
|
||||
if (desc)
|
||||
{
|
||||
text = desc;
|
||||
}
|
||||
else
|
||||
{
|
||||
text = "Assertion: '";
|
||||
text += condition;
|
||||
text += "' failed.";
|
||||
}
|
||||
throw VSTGUI::UnitTest::error (file, lineNo, text.data ());
|
||||
});
|
||||
VSTGUI::init (CFBundleGetMainBundle ());
|
||||
|
||||
auto baseClass = objc_getClass ("XCTestCase");
|
||||
for (auto& testCase : UnitTestRegistry::instance ())
|
||||
{
|
||||
std::string className = "VSTGUI_" + testCase.getName ();
|
||||
auto cls = objc_allocateClassPair (baseClass, className.data (), 0);
|
||||
if (!cls)
|
||||
{
|
||||
NSLog (@"Duplicate TestCase name: %s", testCase.getName ().data ());
|
||||
continue;
|
||||
}
|
||||
class_addIvar (cls, "_testSuite", sizeof (void*), (uint8_t)log2 (sizeof (void*)),
|
||||
@encode (void*));
|
||||
class_addMethod (cls, @selector (setUp), reinterpret_cast<IMP> (setupFunc), "v@:");
|
||||
for (auto& test : testCase)
|
||||
{
|
||||
std::string name = "test" + test.first;
|
||||
auto sel = sel_registerName (name.data ());
|
||||
if (!class_addMethod (cls, sel, reinterpret_cast<IMP> (testFunc), "v@:"))
|
||||
{
|
||||
NSLog (@"Duplicate Method name: %s [%s]", name.data (), className.data ());
|
||||
}
|
||||
}
|
||||
objc_registerClassPair (cls);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user