diff --git a/Translit.xcodeproj/project.pbxproj b/Translit.xcodeproj/project.pbxproj index b38e415..0059069 100644 --- a/Translit.xcodeproj/project.pbxproj +++ b/Translit.xcodeproj/project.pbxproj @@ -30,7 +30,6 @@ 442D25AE2B088B5700204800 /* about.html in Resources */ = {isa = PBXBuildFile; fileRef = 442D25AD2B088B5700204800 /* about.html */; }; 442D25B22B089F2F00204800 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 442D25B12B089F2F00204800 /* WebKit.framework */; }; 442D25B42B0A2E1B00204800 /* Transliterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 445D1E602AFE364900FA1C07 /* Transliterator.cpp */; }; - 442D25BF2B0B2D6600204800 /* TestCommon.mm in Sources */ = {isa = PBXBuildFile; fileRef = 442D25BE2B0B2D6600204800 /* TestCommon.mm */; }; 442D25CA2B0B93D500204800 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 442D25C82B0B93D500204800 /* InfoPlist.strings */; }; 442D25CC2B0CC97100204800 /* Uninstall.mm in Sources */ = {isa = PBXBuildFile; fileRef = 442D25CB2B0CC97100204800 /* Uninstall.mm */; }; 445D1E4C2AFE2C6C00FA1C07 /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 445D1E4B2AFE2C6C00FA1C07 /* AppDelegate.mm */; }; @@ -109,7 +108,6 @@ 442D25BB2B0ADC3A00204800 /* create-release */ = {isa = PBXFileReference; explicitFileType = text.script.python; path = "create-release"; sourceTree = ""; }; 442D25BC2B0ADCB200204800 /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = ""; }; 442D25BD2B0B2D2C00204800 /* TestCommon.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = TestCommon.hpp; sourceTree = ""; }; - 442D25BE2B0B2D6600204800 /* TestCommon.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TestCommon.mm; sourceTree = ""; }; 442D25C02B0B308000204800 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 442D25C12B0B8C6C00204800 /* format-file */ = {isa = PBXFileReference; explicitFileType = text.script.python; path = "format-file"; sourceTree = ""; }; 442D25C62B0B93A500204800 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -361,7 +359,6 @@ 44C675832B02153F003A5BDE /* TestRu.mm */, 44B947CE2B4698E500B68C7E /* TestPerf.mm */, 442D25BD2B0B2D2C00204800 /* TestCommon.hpp */, - 442D25BE2B0B2D6600204800 /* TestCommon.mm */, 4475AD332B131F80008DA122 /* Main.xctestplan */, 4475AD342B132242008DA122 /* Perf.xctestplan */, ); @@ -702,7 +699,6 @@ 44B947D12B469B4C00B68C7E /* TestMapper.mm in Sources */, 44B947CF2B4698E500B68C7E /* TestPerf.mm in Sources */, 44C675842B02153F003A5BDE /* TestRu.mm in Sources */, - 442D25BF2B0B2D6600204800 /* TestCommon.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Translit/tests/TestCommon.hpp b/Translit/tests/TestCommon.hpp index debcd0b..8defa71 100644 --- a/Translit/tests/TestCommon.hpp +++ b/Translit/tests/TestCommon.hpp @@ -8,33 +8,112 @@ #import -struct ResultPayload { - ResultPayload() = default; - ResultPayload(std::u16string_view all_, - size_t completedSize_, - bool matchedSomething_): - all(all_), - completedSize(completedSize_), - matchedSomething(matchedSomething_) - {} - - std::u16string_view all; - size_t completedSize; - bool matchedSomething; - - friend bool operator==(const ResultPayload &, const ResultPayload &) = default; - friend bool operator!=(const ResultPayload &, const ResultPayload &) = default; -}; - -@interface Result : NSObject --(instancetype) initWithPayload:(ResultPayload)payload ; --(instancetype) initWithTransliterator:(const Transliterator &)tr; -@end - -#define XCTAssertTranslit(tr, str, size, matched) \ - XCTAssertEqualObjects([[Result alloc] initWithTransliterator:tr], \ - [[Result alloc] initWithPayload:ResultPayload((str), (size), (matched))]); +#include +#include +namespace TestUtil { + using std::to_string; + + template + concept TestDescriptable = requires(const T & obj) { + { testDescription(obj) } -> std::same_as; + }; + + + template + concept ToStringDescriptable = requires(T obj) { + { to_string(obj) } -> std::same_as; + }; + + + template + concept OStreamDescriptable = requires(T obj, std::ostream & str) { + { str << obj }; + }; + + inline auto demangle(const char * name) -> std::string { + + int status = 0; + std::unique_ptr res { + abi::__cxa_demangle(name, nullptr, nullptr, &status), + std::free + }; + return (status==0) ? res.get() : name ; + } + + template + auto describeForTest(const T & val) { + if constexpr (TestDescriptable) { + return testDescription(val); + } + else if constexpr (ToStringDescriptable) { + using std::to_string; + auto str = to_string(val); + return @(str.c_str()); + } else if constexpr (OStreamDescriptable) { + std::ostringstream str; + str << val; + return @(str.str().c_str()); + } else { + return [NSString stringWithFormat:@"%s object", demangle(typeid(T).name()).c_str()]; + } + } +} + +#define XCTPrimitiveAssertCpp(test, op, type, expression1, expressionStr1, expression2, expressionStr2, ...) \ +({ \ + _XCT_TRY { \ + __typeof__(expression1) expressionValue1 = (expression1); \ + __typeof__(expression2) expressionValue2 = (expression2); \ + if (expressionValue1 != expressionValue2) { \ + _XCTRegisterFailure(test, _XCTFailureDescription(_XCTAssertion_Equal, 0, expressionStr1, expressionStr2, TestUtil::describeForTest(expressionValue1), TestUtil::describeForTest(expressionValue2)), __VA_ARGS__); \ + } \ + } \ + _XCT_CATCH (_XCTestCaseInterruptionException *interruption) { [interruption raise]; } \ + _XCT_CATCH (...) { \ + NSString *_xct_reason = _XCTGetCurrentExceptionReason(); \ + _XCTRegisterUnexpectedFailure(test, _XCTFailureDescription((type), 1, expressionStr1, expressionStr2, _xct_reason), __VA_ARGS__); \ + } \ +}) + +#define XCTAssertCppEqual(expression1, expression2, ...) \ + XCTPrimitiveAssertCpp(nil, !=, _XCTAssertion_Equal, expression1, @#expression1, expression2, @#expression2, __VA_ARGS__) + +#define XCTAssertCppNotEqual(expression1, expression2, ...) \ + XCTPrimitiveAssertCpp(nil, ==, _XCTAssertion_NotEqual, expression1, @#expression1, expression2, @#expression2, __VA_ARGS__) + +#define XCTAssertCppGreaterThan(expression1, expression2, ...) \ + XCTPrimitiveAssertCpp(nil, <=, _XCTAssertion_GreaterThan, expression1, @#expression1, expression2, @#expression2, __VA_ARGS__) + +#define XCTAssertCppGreaterThanOrEqual(expression1, expression2, ...) \ + XCTPrimitiveAssertCpp(nil, <, _XCTAssertion_GreaterThanOrEqual, expression1, @#expression1, expression2, @#expression2, __VA_ARGS__) + +#define XCTAssertCppLessThan(expression1, expression2, ...) \ + XCTPrimitiveAssertCpp(nil, >=, _XCTAssertion_LessThan, expression1, @#expression1, expression2, @#expression2, __VA_ARGS__) + +#define XCTAssertCppLessThanOrEqual(expression1, expression2, ...) \ + XCTPrimitiveAssertCpp(nil, >, _XCTAssertion_LessThanOrEqual, expression1, @#expression1, expression2, @#expression2, __VA_ARGS__) + + +namespace std { + template + auto testDescription(const optional & opt) { + if (opt) + return TestUtil::describeForTest(*opt); + return @"std::nullopt"; + } + + inline auto testDescription(const u16string_view & str) { + return [NSString stringWithCharacters:(const unichar *)str.data() length:str.size()]; + } +} + + +#define XCTAssertTranslit(tr, str, size, matched) ({ \ + XCTAssertCppEqual((tr).result(), (str)); \ + XCTAssertCppEqual((tr).completedSize(), (size)); \ + XCTAssertCppEqual((tr).matchedSomething(), (matched)); \ +}) #endif diff --git a/Translit/tests/TestCommon.mm b/Translit/tests/TestCommon.mm deleted file mode 100644 index 2267888..0000000 --- a/Translit/tests/TestCommon.mm +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2023, Eugene Gershnik -// SPDX-License-Identifier: GPL-3.0-or-later - -#import "TestCommon.hpp" - -@implementation Result { - ResultPayload _payload; -} - - --(instancetype) initWithPayload:(ResultPayload)payload { - - self = [super init]; - if (self) { - _payload = payload; - } - return self; -} - --(instancetype) initWithTransliterator:(const Transliterator &)tr { - self = [super init]; - if (self) { - _payload = ResultPayload{tr.result(), tr.completedSize(), tr.matchedSomething()}; - } - return self; -} - --(BOOL) isEqual:(id)other { - if (other == self) - return YES; - if (!other || ![other isKindOfClass:self.class]) - return NO; - return [self isEqualTo:other]; -} - - --(BOOL) isEqualTo:(Result *)other { - return _payload == other->_payload; -} - --(NSString *) description { - return [NSString stringWithFormat:@"{%@, %zu, %@}", sys_string(_payload.all).ns_str(), size_t(_payload.completedSize), @( _payload.matchedSomething )]; -} - -@end diff --git a/Translit/tests/TestMapper.mm b/Translit/tests/TestMapper.mm index 86603ce..0a6c0b1 100644 --- a/Translit/tests/TestMapper.mm +++ b/Translit/tests/TestMapper.mm @@ -1,7 +1,7 @@ // Copyright (c) 2023, Eugene Gershnik // SPDX-License-Identifier: GPL-3.0-or-later -#import +#include "TestCommon.hpp" #include "../src/Mapper.hpp" @@ -16,26 +16,26 @@ @implementation TestMapper - (void)testOnlyEmptyString { auto mapper = makeMapper(); - XCTAssertEqual(mapper(u""s), 0); - XCTAssertEqual(mapper(u"a"s), 42); + XCTAssertCppEqual(mapper(u""s), 0); + XCTAssertCppEqual(mapper(u"a"s), 42); } - (void)testDisjointStrings { { auto mapper = makeMapper(); - XCTAssertEqual(mapper(u""s), 42); - XCTAssertEqual(mapper(u"a"s), 2); - XCTAssertEqual(mapper(u"b"s), 0); - XCTAssertEqual(mapper(u"c"s), 1); - XCTAssertEqual(mapper(u" "s), 42); + XCTAssertCppEqual(mapper(u""s), 42); + XCTAssertCppEqual(mapper(u"a"s), 2); + XCTAssertCppEqual(mapper(u"b"s), 0); + XCTAssertCppEqual(mapper(u"c"s), 1); + XCTAssertCppEqual(mapper(u" "s), 42); } { auto mapper = makeMapper(); - XCTAssertEqual(mapper(u""s), 42); - XCTAssertEqual(mapper(u"a"s), 42); - XCTAssertEqual(mapper(u"b"s), 42); - XCTAssertEqual(mapper(u"cd"s), 1); + XCTAssertCppEqual(mapper(u""s), 42); + XCTAssertCppEqual(mapper(u"a"s), 42); + XCTAssertCppEqual(mapper(u"b"s), 42); + XCTAssertCppEqual(mapper(u"cd"s), 1); } } @@ -43,29 +43,29 @@ - (void)testDisjointStrings { - (void)testOverlappingStrings { { auto mapper = makeMapper(); - XCTAssertEqual(mapper(u"b"s), 0); - XCTAssertEqual(mapper(u"bc"s), 42); - XCTAssertEqual(mapper(u"bcd"s), 1); + XCTAssertCppEqual(mapper(u"b"s), 0); + XCTAssertCppEqual(mapper(u"bc"s), 42); + XCTAssertCppEqual(mapper(u"bcd"s), 1); } { auto mapper = makeMapper(); - XCTAssertEqual(mapper(u"b"s), 42); - XCTAssertEqual(mapper(u"bc"s), 0); - XCTAssertEqual(mapper(u"bd"s), 1); - XCTAssertEqual(mapper(u"bdd"s), 2); + XCTAssertCppEqual(mapper(u"b"s), 42); + XCTAssertCppEqual(mapper(u"bc"s), 0); + XCTAssertCppEqual(mapper(u"bd"s), 1); + XCTAssertCppEqual(mapper(u"bdd"s), 2); } { auto mapper = makeMapper(); - XCTAssertEqual(mapper("bd"s), 0); - XCTAssertEqual(mapper("bddc"s), 42); - XCTAssertEqual(mapper("bddq"s), 1); + XCTAssertCppEqual(mapper("bd"s), 0); + XCTAssertCppEqual(mapper("bddc"s), 42); + XCTAssertCppEqual(mapper("bddq"s), 1); } } - (void)testRepeatedStrings { constexpr auto mapper = makeMapper(); - XCTAssertEqual(mapper("ab"sv), 2); - XCTAssertEqual(mapper("cd"sv), 1); + XCTAssertCppEqual(mapper("ab"sv), 2); + XCTAssertCppEqual(mapper("cd"sv), 1); } diff --git a/Translit/tests/TestPrefixMapper.mm b/Translit/tests/TestPrefixMapper.mm index 726f755..51a04f3 100644 --- a/Translit/tests/TestPrefixMapper.mm +++ b/Translit/tests/TestPrefixMapper.mm @@ -1,12 +1,20 @@ // Copyright (c) 2023, Eugene Gershnik // SPDX-License-Identifier: GPL-3.0-or-later -#import +#include "TestCommon.hpp" #include "../src/Mapper.hpp" using namespace std::literals; +#define XCTAssertPrefixMap(mapper, text, exp_payload, exp_definite, exp_next) ({ \ + auto str = text; \ + auto res = mapper(str); \ + XCTAssertCppEqual(res.payload, (exp_payload)); \ + XCTAssertCppEqual(res.definite, (exp_definite)); \ + XCTAssertCppEqual(res.next - str.begin(), (exp_next)); \ +}) + @interface TestPrefixMapper : XCTestCase @end @@ -23,111 +31,32 @@ - (void)tearDown { - (void)testEmpty { auto mapper = nullPrefixMapper; - { - auto str = u""s; - auto res = mapper(str); - XCTAssertEqual(res.payload, std::nullopt); - XCTAssertEqual(res.definite, true); - XCTAssertEqual(res.next, str.begin()); - } - { - auto str = u"a"s; - auto res = mapper(str); - XCTAssertEqual(res.payload, std::nullopt); - XCTAssertEqual(res.definite, true); - XCTAssertEqual(res.next, str.begin()); - } + XCTAssertPrefixMap(mapper, u""s, std::nullopt, true, 0); + XCTAssertPrefixMap(mapper, u"a"s, std::nullopt, true, 0); } - (void)testOnlyEmptyString { auto mapper = makePrefixMapper(); - { - auto str = u""s; - auto res = mapper(str); - XCTAssertEqual(res.payload, 0); - XCTAssertEqual(res.definite, true); - XCTAssertEqual(res.next, str.begin()); - } - { - auto str = u"a"s; - auto res = mapper(str); - XCTAssertEqual(res.payload, 0); - XCTAssertEqual(res.definite, true); - XCTAssertEqual(res.next, str.begin()); - } + XCTAssertPrefixMap(mapper, u""s, 0, true, 0); + XCTAssertPrefixMap(mapper, u"a"s, 0, true, 0); } - (void)testDisjointStrings { { - auto mapper = makePrefixMapper(); - { - auto str = u""s; - auto res = mapper(str); - XCTAssertEqual(res.payload, std::nullopt); - XCTAssertEqual(res.definite, false); - XCTAssertEqual(res.next, str.begin()); - } - { - auto str = u"a"s; - auto res = mapper(str); - XCTAssertEqual(res.payload, 2); - XCTAssertEqual(res.definite, true); - XCTAssertEqual(res.next, str.end()); - } - { - auto str = u"b"s; - auto res = mapper(str); - XCTAssertEqual(res.payload, 0); - XCTAssertEqual(res.definite, true); - XCTAssertEqual(res.next, str.end()); - } - { - auto str = u"c"s; - auto res = mapper(str); - XCTAssertEqual(res.payload, 1); - XCTAssertEqual(res.definite, true); - XCTAssertEqual(res.next, str.end()); - } - { - auto str = u" "s; - auto res = mapper(str); - XCTAssertEqual(res.payload, std::nullopt); - XCTAssertEqual(res.definite, true); - XCTAssertEqual(res.next, str.begin()); - } + XCTAssertPrefixMap(mapper, u""s, std::nullopt, false, 0); + XCTAssertPrefixMap(mapper, u"a"s, 2, true, 1); + XCTAssertPrefixMap(mapper, u"b"s, 0, true, 1); + XCTAssertPrefixMap(mapper, u"c"s, 1, true, 1); + XCTAssertPrefixMap(mapper, u" "s, std::nullopt, true, 0); } { auto mapper = makePrefixMapper(); - { - auto str = u""s; - auto res = mapper(str); - XCTAssertEqual(res.payload, std::nullopt); - XCTAssertEqual(res.definite, false); - XCTAssertEqual(res.next, str.begin()); - } - { - auto str = u"a"s; - auto res = mapper(str); - XCTAssertEqual(res.payload, std::nullopt); - XCTAssertEqual(res.definite, false); - XCTAssertEqual(res.next, str.begin()); - } - { - auto str = u"b"s; - auto res = mapper(str); - XCTAssertEqual(res.payload, std::nullopt); - XCTAssertEqual(res.definite, true); - XCTAssertEqual(res.next, str.begin()); - } - { - auto str = u"cd"s; - auto res = mapper(str); - XCTAssertEqual(res.payload, 1); - XCTAssertEqual(res.definite, true); - XCTAssertEqual(res.next, str.end()); - } + XCTAssertPrefixMap(mapper, u""s, std::nullopt, false, 0); + XCTAssertPrefixMap(mapper, u"a"s, std::nullopt, false, 0); + XCTAssertPrefixMap(mapper, u"b"s, std::nullopt, true, 0); + XCTAssertPrefixMap(mapper, u"cd"s, 1, true, 2); } } @@ -135,89 +64,27 @@ - (void)testDisjointStrings { - (void)testOverlappingStrings { { auto mapper = makePrefixMapper(); - { - auto str = u"b"s; - auto res = mapper(str); - XCTAssertEqual(res.payload, 0); - XCTAssertEqual(res.definite, false); - XCTAssertEqual(res.next, str.begin() + 1); - } - { - auto str = u"bc"s; - auto res = mapper(str); - XCTAssertEqual(res.payload, 0); - XCTAssertEqual(res.definite, false); - XCTAssertEqual(res.next, str.begin() + 1); - } - { - auto str = u"bcd"s; - auto res = mapper(str); - XCTAssertEqual(res.payload, 1); - XCTAssertEqual(res.definite, true); - XCTAssertEqual(res.next, str.begin() + 3); - } + XCTAssertPrefixMap(mapper, u"b"s, 0, false, 1); + XCTAssertPrefixMap(mapper, u"bc"s, 0, false, 1); + XCTAssertPrefixMap(mapper, u"bcd"s, 1, true, 3); } { auto mapper = makePrefixMapper(); - { - auto str = u"b"s; - auto res = mapper(str); - XCTAssertEqual(res.payload, std::nullopt); - XCTAssertEqual(res.definite, false); - XCTAssertEqual(res.next, str.begin()); - } - { - auto str = u"bc"s; - auto res = mapper(str); - XCTAssertEqual(res.payload, 0); - XCTAssertEqual(res.definite, true); - XCTAssertEqual(res.next, str.begin() + 2); - } - { - auto str = u"bd"s; - auto res = mapper(str); - XCTAssertEqual(res.payload, 1); - XCTAssertEqual(res.definite, false); - XCTAssertEqual(res.next, str.begin() + 2); - } - { - auto str = u"bdd"s; - auto res = mapper(str); - XCTAssertEqual(res.payload, 2); - XCTAssertEqual(res.definite, true); - XCTAssertEqual(res.next, str.begin() + 3); - } + XCTAssertPrefixMap(mapper, u"b"s, std::nullopt, false, 0); + XCTAssertPrefixMap(mapper, u"bc"s, 0, true, 2); + XCTAssertPrefixMap(mapper, u"bd"s, 1, false, 2); + XCTAssertPrefixMap(mapper, u"bdd"s, 2, true, 3); } { auto mapper = makePrefixMapper(); - { - auto str = "bddc"s; - auto res = mapper(str); - XCTAssertEqual(res.payload, 0); - XCTAssertEqual(res.definite, true); - XCTAssertEqual(res.next, str.begin() + 2); - } - + XCTAssertPrefixMap(mapper, "bddc"s, 0, true, 2); } } - (void)testRepeatedStrings { constexpr auto mapper = makePrefixMapper(); - - { - constexpr auto str = "ab"sv; - auto res = mapper(str); - XCTAssertEqual(res.payload, 2); - XCTAssertEqual(res.definite, true); - XCTAssertEqual(res.next, str.end()); - } - { - constexpr auto str = "cd"sv; - auto res = mapper(str); - XCTAssertEqual(res.payload, 1); - XCTAssertEqual(res.definite, true); - XCTAssertEqual(res.next, str.end()); - } + XCTAssertPrefixMap(mapper, "ab"sv, 2, true, 2); + XCTAssertPrefixMap(mapper, "cd"sv, 1, true, 2); }