diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 4b53150b..d358ff4e 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -2,9 +2,6 @@ name: Build on: [push, pull_request] -env: - BUILD_TYPE: Release - jobs: build-linux-gcc: name: Linux (GCC) (Unity) @@ -13,11 +10,11 @@ jobs: - uses: actions/checkout@v3 - name: Install Dependencies - run: sudo apt -y install libncursesw5-dev libgpm-dev + run: sudo apt -y install libncursesw5-dev libgpm-dev libgtest-dev - name: Configure CMake shell: bash - run: cmake . -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DTV_REDUCE_APP_SIZE=ON -DTV_LIBRARY_UNITY_BUILD=ON + run: cmake . -DCMAKE_BUILD_TYPE=Release -DTV_BUILD_TESTS=ON -DTV_REDUCE_APP_SIZE=ON -DTV_LIBRARY_UNITY_BUILD=ON - name: Build shell: bash @@ -42,7 +39,7 @@ jobs: env: CC: gcc-5 CXX: g++-5 - run: cmake . -DCMAKE_BUILD_TYPE=$BUILD_TYPE + run: cmake . -DCMAKE_BUILD_TYPE=Release - name: Build shell: bash @@ -62,12 +59,34 @@ jobs: env: CC: clang CXX: clang++ - run: cmake . -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DTV_OPTIMIZE_BUILD=OFF + run: cmake . -DCMAKE_BUILD_TYPE=Release -DTV_OPTIMIZE_BUILD=OFF - name: Build shell: bash run: cmake --build . -j$(nproc) + build-linux-big-endian: + name: Linux (GCC) (Big Endian) + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + + - name: Build in container + uses: uraimo/run-on-arch-action@v2 + with: + arch: s390x + distro: alpine_latest + dockerRunArgs: | + --volume "${PWD}:/app" + env: | + LC_CTYPE: C.UTF-8 + shell: /bin/sh + install: apk update && apk add make cmake g++ ncurses-dev gtest-dev linux-headers + run: | + cd /app + cmake . -DCMAKE_BUILD_TYPE= -DTV_BUILD_USING_GPM=OFF -DTV_BUILD_EXAMPLES=OFF -DTV_BUILD_TESTS=ON -DTV_LIBRARY_UNITY_BUILD=ON + cmake --build . -j$(nproc) + build-windows-msvc32: name: Windows (MSVC) (Win32) runs-on: windows-latest @@ -160,7 +179,7 @@ jobs: - name: Configure CMake shell: bash - run: cmake . -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_FLAGS="-static" -DTV_OPTIMIZE_BUILD=OFF + run: cmake . -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE= -DCMAKE_CXX_FLAGS="-static" -DTV_LIBRARY_UNITY_BUILD=ON - name: Build shell: bash @@ -211,7 +230,7 @@ jobs: - name: Configure CMake shell: bash - run: cmake . -DCMAKE_BUILD_TYPE=$BUILD_TYPE + run: cmake . -DCMAKE_BUILD_TYPE=Release - name: Build shell: bash diff --git a/examples/tvdemo/tvdemo3.cpp b/examples/tvdemo/tvdemo3.cpp index 1bd90d1c..0c5944d4 100644 --- a/examples/tvdemo/tvdemo3.cpp +++ b/examples/tvdemo/tvdemo3.cpp @@ -48,10 +48,12 @@ void TVDemo::mouse() if (mouseCage != 0) { + int32_t mouseReverse = TEventQueue::mouseReverse; mouseCage->helpCtx = hcOMMouseDBox; - mouseCage->setData(&(TEventQueue::mouseReverse)); + mouseCage->setData(&mouseReverse); if (deskTop->execView(mouseCage) != cmCancel) - mouseCage->getData(&(TEventQueue::mouseReverse)); + mouseCage->getData(&mouseReverse); + TEventQueue::mouseReverse = mouseReverse; } destroy( mouseCage ); diff --git a/include/tvision/colors.h b/include/tvision/colors.h index f19d8201..f0beac83 100644 --- a/include/tvision/colors.h +++ b/include/tvision/colors.h @@ -57,20 +57,34 @@ inline TColorAttr reverseAttribute(TColorAttr attr) struct TColorRGB { uint32_t +#ifndef TV_BIG_ENDIAN b : 8, g : 8, r : 8, _unused : 8; +#else + _unused : 8, + r : 8, + g : 8, + b : 8; +#endif TV_TRIVIALLY_CONVERTIBLE(TColorRGB, uint32_t, 0xFFFFFF) constexpr inline TColorRGB(uint8_t r, uint8_t g, uint8_t b); }; constexpr inline TColorRGB::TColorRGB(uint8_t r, uint8_t g, uint8_t b) : +#ifndef TV_BIG_ENDIAN b(b), g(g), r(r), _unused(0) +#else + _unused(0), + r(r), + g(g), + b(b) +#endif { } @@ -90,11 +104,19 @@ constexpr inline TColorRGB::TColorRGB(uint8_t r, uint8_t g, uint8_t b) : struct TColorBIOS { uint8_t +#ifndef TV_BIG_ENDIAN b : 1, g : 1, r : 1, bright : 1, _unused : 4; +#else + _unused : 4, + bright : 1, + r : 1, + g : 1, + b : 1; +#endif TV_TRIVIALLY_CONVERTIBLE(TColorBIOS, uint8_t, 0xF) }; diff --git a/include/tvision/compat/windows/windows.h b/include/tvision/compat/windows/windows.h index 253fe1ea..f98c9785 100644 --- a/include/tvision/compat/windows/windows.h +++ b/include/tvision/compat/windows/windows.h @@ -204,7 +204,11 @@ typedef struct _KEY_EVENT_RECORD { WORD wVirtualScanCode; union { WCHAR UnicodeChar; +#ifndef TV_BIG_ENDIAN CHAR AsciiChar; +#else + struct { WCHAR : 8*sizeof(WCHAR) - 8, AsciiChar : 8; }; +#endif } uChar; DWORD dwControlKeyState; } KEY_EVENT_RECORD; diff --git a/include/tvision/internal/ansidisp.h b/include/tvision/internal/ansidisp.h index b39fdcc8..b86f002a 100644 --- a/include/tvision/internal/ansidisp.h +++ b/include/tvision/internal/ansidisp.h @@ -5,6 +5,7 @@ #include #include +#include namespace tvision { @@ -30,6 +31,9 @@ struct TermColor TermColor& operator=(uint32_t val) noexcept { +#ifdef TV_BIG_ENDIAN + reverseBytes(val); +#endif memcpy(this, &val, sizeof(*this)); return *this; static_assert(sizeof(*this) == 4, ""); @@ -38,6 +42,9 @@ struct TermColor { uint32_t val; memcpy(&val, this, sizeof(*this)); +#ifdef TV_BIG_ENDIAN + reverseBytes(val); +#endif return val; } TermColor(uint8_t aIdx, TermColorTypes aType) noexcept diff --git a/include/tvision/internal/endian.h b/include/tvision/internal/endian.h new file mode 100644 index 00000000..932366da --- /dev/null +++ b/include/tvision/internal/endian.h @@ -0,0 +1,32 @@ +#ifndef TVISION_ENDIAN_H +#define TVISION_ENDIAN_H + +#include + +namespace tvision +{ + +// Optimization: the 'reverseBytes' methods are written in such a way that the +// compiler will likely replace them with a BSWAP instruction or equivalent. + +inline void reverseBytes(uint16_t &val) +{ + val = (val << 8) | (val >> 8); +} + +inline void reverseBytes(uint32_t &val) +{ + val = ((val << 8) & 0xFF00FF00U) | ((val >> 8) & 0x00FF00FF); + val = (val << 16) | (val >> 16); +} + +inline void reverseBytes(uint64_t &val) +{ + val = ((val << 8) & 0xFF00FF00FF00FF00ULL) | ((val >> 8) & 0x00FF00FF00FF00FFULL); + val = ((val << 16) & 0xFFFF0000FFFF0000ULL) | ((val >> 16) & 0x0000FFFF0000FFFFULL); + val = (val << 32) | (val >> 32); +} + +} // namespace tvision + +#endif // TVISION_ENDIAN_H diff --git a/include/tvision/internal/strings.h b/include/tvision/internal/strings.h index 0cb8254e..750414d1 100644 --- a/include/tvision/internal/strings.h +++ b/include/tvision/internal/strings.h @@ -1,19 +1,17 @@ #ifndef TVISION_STRINGS_H #define TVISION_STRINGS_H -#ifndef _TV_VERSION #include -#endif namespace tvision { template inline constexpr Int string_as_int(TStringView s) noexcept +// CAUTION: It is not endian-safe to reinterpret the result as an array of bytes. { Int res = 0; for (size_t i = 0; i < min(s.size(), sizeof(res)); ++i) - // CAUTION: Assumes Little Endian. res |= uint64_t(uint8_t(s[i])) << 8*i; return res; } @@ -32,15 +30,15 @@ struct alignas(4) btoa_lut_elem_t using btoa_lut_t = constarray; inline char *fast_btoa(uint8_t value, char *buffer) noexcept +// Pre: the capacity of 'buffer' is at least 4 bytes. { extern const btoa_lut_t btoa_lut; const auto &lut = (btoa_lut_elem_t (&) [256]) btoa_lut; - // CAUTION: Assumes Little Endian. - // We can afford to write more bytes into 'buffer' than digits. - uint32_t asInt; - memcpy(&asInt, &lut[value], 4); - memcpy(buffer, &asInt, 4); - return buffer + (asInt >> 24); + // Optimization: read and write the whole LUT entry at once in order to + // minimize memory accesses. We can afford to write more bytes into 'buffer' + // than digits. + memcpy(buffer, &lut[value], 4); + return buffer + (uint8_t) buffer[3]; static_assert(sizeof(btoa_lut_elem_t) == 4, ""); } diff --git a/include/tvision/internal/utf8.h b/include/tvision/internal/utf8.h index df02c5a9..f8800a99 100644 --- a/include/tvision/internal/utf8.h +++ b/include/tvision/internal/utf8.h @@ -1,7 +1,9 @@ #ifndef TVISION_UTF8_H #define TVISION_UTF8_H -#include +#include + +#include #include #include @@ -66,6 +68,9 @@ inline size_t utf32To8(uint32_t u32, char u8[4]) noexcept (( u32 & 0b00111111) | 0b10000000) << 24; length = 4; } +#ifdef TV_BIG_ENDIAN + reverseBytes(asInt); +#endif memcpy(u8, &asInt, 4); return length; } diff --git a/include/tvision/scrncell.h b/include/tvision/scrncell.h index f2f8fef3..bb63925a 100644 --- a/include/tvision/scrncell.h +++ b/include/tvision/scrncell.h @@ -76,13 +76,14 @@ struct TCellChar inline void TCellChar::moveChar(char ch) { - moveInt((uchar) ch); + memset(this, 0, sizeof(*this)); + _text[0] = ch; } inline void TCellChar::moveInt(uint32_t mbc, bool wide) +// Pre: 'mbc' is a bit-casted multibyte-encoded character. { memset(this, 0, sizeof(*this)); - // CAUTION: Assumes Little Endian. memcpy(_text, &mbc, sizeof(mbc)); _flags = -int(wide) & fWide; } diff --git a/include/tvision/system.h b/include/tvision/system.h index 71a65bbe..1244fecd 100644 --- a/include/tvision/system.h +++ b/include/tvision/system.h @@ -187,8 +187,15 @@ inline void TMouse::registerHandler( unsigned mask, void (_FAR *func)() ) struct CharScanType { +#if !defined( TV_BIG_ENDIAN ) uchar charCode; uchar scanCode; +#else + // Due to the reverse byte order, swap the fields in order to preserve + // the aliasing with KeyDownEvent::keyCode. + uchar scanCode; + uchar charCode; +#endif }; struct KeyDownEvent @@ -222,11 +229,21 @@ struct MessageEvent union { void *infoPtr; +#if !defined( TV_BIG_ENDIAN ) int32_t infoLong; ushort infoWord; short infoInt; uchar infoByte; char infoChar; +#else + // Due to the reverse byte order, add padding at the beginning to + // preserve the aliasing with infoPtr. + struct { intptr_t : 8*sizeof(infoPtr) - 32, infoLong : 32; }; + struct { uintptr_t : 8*sizeof(infoPtr) - 16, infoWord : 16; }; + struct { intptr_t : 8*sizeof(infoPtr) - 16, infoInt : 16; }; + struct { uintptr_t : 8*sizeof(infoPtr) - 8, infoByte : 8; }; + struct { intptr_t : 8*sizeof(infoPtr) - 8, infoChar : 8; }; +#endif }; }; diff --git a/include/tvision/ttypes.h b/include/tvision/ttypes.h index f5ccea7b..8c4fbccd 100644 --- a/include/tvision/ttypes.h +++ b/include/tvision/ttypes.h @@ -50,6 +50,8 @@ typedef long int32_t; typedef uchar uint8_t; typedef ushort uint16_t; typedef ulong uint32_t; +typedef long intptr_t; +typedef ulong uintptr_t; #endif #ifdef __BORLANDC__ diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index c1f891d6..253e3f22 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -74,6 +74,17 @@ target_compile_definitions(${PROJECT_NAME} PRIVATE TVISION_NO_STL ) +include(TestBigEndian) + +TEST_BIG_ENDIAN(IS_BIG_ENDIAN) + +if (IS_BIG_ENDIAN) + tv_message(STATUS "Big endian system detected") + target_compile_definitions(${PROJECT_NAME} PUBLIC + TV_BIG_ENDIAN + ) +endif() + # Dependencies if (NOT WIN32) @@ -172,6 +183,7 @@ if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.16.0" AND TV_OPTIMIZE_BUILD) file(GLOB_RECURSE TVSOURCE_NOUNITY "${CMAKE_CURRENT_LIST_DIR}/tvision/s*.cpp") list(APPEND TVSOURCE_NOUNITY "${CMAKE_CURRENT_LIST_DIR}/tvision/new.cpp") list(REMOVE_ITEM TVSOURCE_NOUNITY + "${CMAKE_CURRENT_LIST_DIR}/tvision/snprintf.cpp" "${CMAKE_CURRENT_LIST_DIR}/tvision/stddlg.cpp" "${CMAKE_CURRENT_LIST_DIR}/tvision/strmstat.cpp" "${CMAKE_CURRENT_LIST_DIR}/tvision/syserr.cpp" diff --git a/source/platform/ansidisp.cpp b/source/platform/ansidisp.cpp index bbb1237a..6b813966 100644 --- a/source/platform/ansidisp.cpp +++ b/source/platform/ansidisp.cpp @@ -158,7 +158,11 @@ struct alignas(8) colorconv_r colorconv_r() = default; colorconv_r(TermColor aColor, TColorAttr::Style aExtraFlags=0) noexcept { + // Optimization: do bit-casting manually, just like with TermColor. uint64_t val = aColor | (uint64_t(aExtraFlags) << 32); +#ifdef TV_BIG_ENDIAN + reverseBytes(val); +#endif memcpy(this, &val, 8); static_assert(sizeof(*this) == 8, ""); } diff --git a/source/platform/buffdisp.cpp b/source/platform/buffdisp.cpp index a2a3621d..666e1f90 100644 --- a/source/platform/buffdisp.cpp +++ b/source/platform/buffdisp.cpp @@ -340,7 +340,7 @@ inline void FlushScreenAlgorithm::writeCell() noexcept inline void FlushScreenAlgorithm::writeSpace() noexcept { TCellChar ch; - ch.moveInt(' '); + ch.moveChar(' '); writeCell(ch, cell->attr, 0); } diff --git a/source/platform/far2l.cpp b/source/platform/far2l.cpp index bda55b6d..b9cff0a3 100644 --- a/source/platform/far2l.cpp +++ b/source/platform/far2l.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -97,6 +98,16 @@ ParseResult parseFar2lInput(GetChBuf &buf, TEvent &ev, InputState &state) noexce memcpy(&kev.dwControlKeyState, &out[6], 4); memcpy(&kev.uChar.UnicodeChar, &out[10], 4); +#ifdef TV_BIG_ENDIAN + // The protocol states that "all integer values are in + // little-endian format", so convert them. + reverseBytes(kev.wRepeatCount); + reverseBytes(kev.wVirtualKeyCode); + reverseBytes(kev.wVirtualScanCode); + reverseBytes(kev.dwControlKeyState); + reverseBytes((uint32_t &) kev.uChar.UnicodeChar); +#endif + if (uint16_t keyCode = virtualKeyCodeToKeyCode[kev.wVirtualKeyCode]) { kev.wVirtualScanCode = keyCode >> 8; @@ -120,6 +131,14 @@ ParseResult parseFar2lInput(GetChBuf &buf, TEvent &ev, InputState &state) noexce memcpy(&mev.dwControlKeyState, &out[8], 4); memcpy(&mev.dwEventFlags, &out[12], 4); +#ifdef TV_BIG_ENDIAN + reverseBytes((uint16_t &) mev.dwMousePosition.X); + reverseBytes((uint16_t &) mev.dwMousePosition.Y); + reverseBytes(mev.dwButtonState); + reverseBytes(mev.dwControlKeyState); + reverseBytes(mev.dwEventFlags); +#endif + getWin32Mouse(mev, ev, state); return Accepted; } @@ -143,6 +162,9 @@ ParseResult parseFar2lAnswer(GetChBuf &buf, TEvent &ev, InputState &state) noexc { uint32_t dataSize; memcpy(&dataSize, &decoded[decoded.size() - 5], 4); +#ifdef TV_BIG_ENDIAN + reverseBytes(dataSize); +#endif if (dataSize < UINT_MAX - 5 && decoded.size() >= 5 + dataSize) { TStringView text = decoded.substr(decoded.size() - 5 - dataSize, dataSize); @@ -195,7 +217,12 @@ inline size_t concat(char *out, uint32_t i, Args ...args) noexcept { size_t len = sizeof(i); if (write) + { +#ifdef TV_BIG_ENDIAN + reverseBytes(i); +#endif memcpy(out, &i, len); + } return len + concat(out + len, args...); } diff --git a/source/tvision/tview.cpp b/source/tvision/tview.cpp index 777de249..7d195be1 100644 --- a/source/tvision/tview.cpp +++ b/source/tvision/tview.cpp @@ -725,12 +725,13 @@ void TView::putInFrontOf( TView *Target ) void TView::select() { - if( ! (options & ofSelectable)) - return; - if( (options & ofTopSelect) != 0 ) - makeFirst(); - else if( owner != 0 ) - owner->setCurrent( this, normalSelect ); + if( (options & ofSelectable) != 0 && owner != 0 ) + { + if( (options & ofTopSelect) != 0 ) + makeFirst(); + else + owner->setCurrent( this, normalSelect ); + } } void TView::setBounds( const TRect& bounds ) noexcept diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 64b50af5..502f847e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -36,4 +36,8 @@ if (TV_BUILD_TESTS) ) add_custom_target(${PROJECT_NAME}-test-run ALL DEPENDS ${PROJECT_NAME}-test-passed) + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.16.0" AND TV_OPTIMIZE_BUILD) + target_precompile_headers(${PROJECT_NAME}-test PRIVATE "${CMAKE_CURRENT_LIST_DIR}/test.h") + tv_enable_unity(${PROJECT_NAME}-test) + endif() endif() diff --git a/test/platform/endian.test.cpp b/test/platform/endian.test.cpp new file mode 100644 index 00000000..6b86f757 --- /dev/null +++ b/test/platform/endian.test.cpp @@ -0,0 +1,82 @@ +#define Uses_TColorAttr +#define Uses_TEvent +#define Uses_TWindow +#include + +#include + +#include + +namespace tvision +{ + +TEST(Endianess, AliasingInKeyDownEventShouldWorkCorrectly) +{ + KeyDownEvent keyDown {}; + keyDown.keyCode = 0x1234; + EXPECT_EQ(keyDown.charScan.charCode, 0x34); + EXPECT_EQ(keyDown.charScan.scanCode, 0x12); +} + +TEST(Endianess, AliasingInMessageEventShouldWorkCorrectly) +{ + MessageEvent message {}; + message.infoPtr = (void *) 0x12345678; + + EXPECT_EQ(message.infoByte, 0x78); + EXPECT_EQ(message.infoChar, 0x78); + EXPECT_EQ(message.infoWord, 0x5678); + EXPECT_EQ(message.infoInt, 0x5678); + EXPECT_EQ(message.infoLong, 0x12345678); +} + +TEST(Endianess, TWindowShouldHandleSelectCommand) +{ + short number = 1; + TWindow window(TRect(0, 0, 0, 0), nullptr, number); + + void *response = message(&window, evBroadcast, cmSelectWindowNum, (void *)(size_t) number); + EXPECT_EQ(response, &window); + + window.shutDown(); +} + +TEST(Endianess, ColorsWithBitFieldsShouldBehaveAsExpected) +{ + TColorRGB rgb = 0x112233; + EXPECT_EQ(rgb.r, 0x11); + EXPECT_EQ(rgb.g, 0x22); + EXPECT_EQ(rgb.b, 0x33); + + TColorBIOS bios = 0x3; + EXPECT_EQ(bios.b, 1); + EXPECT_EQ(bios.g, 1); + EXPECT_EQ(bios.r, 0); + EXPECT_EQ(bios.bright, 0); + + bios = 0xC; + EXPECT_EQ(bios.b, 0); + EXPECT_EQ(bios.g, 0); + EXPECT_EQ(bios.r, 1); + EXPECT_EQ(bios.bright, 1); +} + +TEST(Endianess, TermColorShouldBehaveAsExpected) +{ + TColorRGB rgb = 0x123456; + TermColor termRgb {rgb, TermColor::RGB}; + EXPECT_EQ(termRgb.type, TermColor::RGB); + EXPECT_EQ(termRgb.bgr[0], 0x56); + EXPECT_EQ(termRgb.bgr[1], 0x34); + EXPECT_EQ(termRgb.bgr[2], 0x12); + + uint8_t idx = 15; + TermColor termIdx {idx, TermColor::Indexed}; + EXPECT_EQ(termIdx.type, TermColor::Indexed); + EXPECT_EQ(termIdx.idx, idx); + + TermColor termNoColor {TermColor::NoColor}; + EXPECT_EQ(termNoColor.type, TermColor::NoColor); +} + +} // namespace tvision diff --git a/test/platform/far2l.test.cpp b/test/platform/far2l.test.cpp index 731ac1af..fee62b51 100644 --- a/test/platform/far2l.test.cpp +++ b/test/platform/far2l.test.cpp @@ -12,7 +12,7 @@ namespace tvision const ushort kbS = 0x1f73, kb9 = 0x0a39; -TEST(Far2l, ShouldReadFar2lKeys) +TEST(Far2l, ShouldReadFar2lInput) { static constexpr char longString[1024*1024] = {0}; static const TestCase testCases[] = @@ -32,6 +32,10 @@ TEST(Far2l, ShouldReadFar2lKeys) {"AQBWAAAACgAAAFYAAABL\x07", {Accepted, keyDownEv(kbAltV, kbLeftCtrl | kbLeftAlt, "")}}, {"AQBWAAAACgAAAAAAAABL\x07", {Ignored}}, // AltGr + V, UnicodeChar = 0 {"AQAMAAAAIgAAAAAAAABL\x07", {Ignored}}, // Alt + VK_CLEAR + {"AAAGAAAAAAAAAAAAAQAAAE0=\x07", {Accepted, mouseEv({0, 6}, meMouseMoved, 0, 0, 0)}}, + {"CQANAAQAAAAAAAAAAAAAAE0=\x07", {Accepted, mouseEv({9, 13}, 0, 0, mbMiddleButton, 0)}}, + {"CQANAAAAAAAAAAAAAAAAAE0=\x07", {Accepted, mouseEv({9, 13}, 0, 0, 0, 0)}}, // Button release. + {"AAAAAAAAAAAAAAAAAAAAAE0=\x07", {Accepted, mouseEv({0, 0}, 0, 0, 0, 0)}}, // Button release. }; for (auto &testCase : testCases) diff --git a/test/platform/terminal.test.cpp b/test/platform/terminal.test.cpp index 43b26363..2d8774ba 100644 --- a/test/platform/terminal.test.cpp +++ b/test/platform/terminal.test.cpp @@ -66,7 +66,7 @@ TEST(TermIO, ShouldReadWin32InputModeKeys) {"\x1B[112;59;0;0;8;1_", {}}, // https://github.com/microsoft/terminal/issues/15083 { // SGR mouse event - "\x1B[0;0;27;1;0;1_" + "\x1B[0;0;27;1;0;1_" // \x1B[<0;52;12M "\x1B[0;0;91;1;0;1_" "\x1B[0;0;60;1;0;1_" "\x1B[0;0;48;1;0;1_" diff --git a/test/platform/utf8.test.cpp b/test/platform/utf8.test.cpp index 1c478ddf..5728b35a 100644 --- a/test/platform/utf8.test.cpp +++ b/test/platform/utf8.test.cpp @@ -10,18 +10,20 @@ TEST(Utf8, ShouldConvertUtf16StringToUtf8) static const TestCase, TStringView> testCases[] = { {"", ""}, - {"\x61\x00\x62\x00\x63\x00\x64\x00", "abcd"}, - {"\x6F\x00\x3D\xD8\x95\xDC\x57\x00", "o💕W"}, + // Use Unicode string literals so that the resulting UTF-16 characters + // are encoded using the system's native endianess. + {(const char (&)[8]) u"\u0061\u0062\u0063\u0064", "abcd"}, + {(const char (&)[8]) u"\u006F\U0001F495\u0057", "o💕W"}, }; for (auto &testCase : testCases) { - TSpan input { + TSpan u16Input { (const uint16_t *) testCase.input.data(), testCase.input.size()/2, }; - char *buf = new char[input.size()*3]; - size_t length = utf16To8(input, buf); + char *buf = new char[u16Input.size()*3]; + size_t length = utf16To8(u16Input, buf); TStringView actual {buf, length}; expectResultMatches(actual, testCase); delete[] buf;