diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e037b3f49..e9c91316e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -231,3 +231,19 @@ jobs: run: haxe compile-cpp.hxml -D ${{ env.HXCPP_ARCH_FLAG }} -D no_http - name: run run: bin${{ inputs.sep }}cpp${{ inputs.sep }}TestMain-debug + + regression: + runs-on: ${{ inputs.os }} + name: regression tests + defaults: + run: + working-directory: test/regression + steps: + - name: checkout + uses: actions/checkout@v4 + - name: setup + uses: ./.github/workflows/setup + with: + haxe: ${{ inputs.haxe }} + - name: run + run: haxe --run Run -D ${{ env.HXCPP_ARCH_FLAG }} diff --git a/include/hxString.h b/include/hxString.h index b53ddd4a3..b0ef9e8d3 100644 --- a/include/hxString.h +++ b/include/hxString.h @@ -42,6 +42,7 @@ class HXCPP_EXTERN_CLASS_ATTRIBUTES String inline String(const char16_t *inPtr) { *this = create(inPtr); } inline String(const char *inPtr) { *this = create(inPtr); } + // If inLen is -1, the input string is treated as null terminated. static String create(const wchar_t *inPtr,int inLen=-1); static String create(const char16_t *inPtr,int inLen=-1); static String create(const char *inPtr,int inLen=-1); diff --git a/src/String.cpp b/src/String.cpp index 4dc69a23b..4473d845b 100644 --- a/src/String.cpp +++ b/src/String.cpp @@ -446,9 +446,6 @@ inline String TCopyString(const T *inString,int inLength) return String(); #ifndef HX_SMART_STRINGS - if (inLength<0) - for(inLength=0; !inString[inLength]; inString++) { } - if (sizeof(T)==1) { int len = 0; @@ -457,7 +454,10 @@ inline String TCopyString(const T *inString,int inLength) } else { - int length = inLength; + if (inLength == 0) { + return String::emptyString; + } + int length = inLength > 0 ? inLength : 0; const char *ptr = TConvertToUTF8(inString, &length, 0, true ); return String(ptr,length); } diff --git a/test/regression/Issue849/Main.hx b/test/regression/Issue849/Main.hx new file mode 100644 index 000000000..f2e758d2f --- /dev/null +++ b/test/regression/Issue849/Main.hx @@ -0,0 +1,21 @@ +function main() { + // char + trace(untyped __cpp__('::String::create("Hello world")')); + + // wchar_t + trace(untyped __cpp__('::String::create(L"Hello world")')); + + // char16_t + trace(untyped __cpp__('::String::create(u"Hello world")')); + + // explicit 0 length + + // char + trace(untyped __cpp__('::String::create("Hello world", 0)')); + + // wchar_t + trace(untyped __cpp__('::String::create(L"Hello world", 0)')); + + // char16_t + trace(untyped __cpp__('::String::create(u"Hello world", 0)')); +} diff --git a/test/regression/Issue849/build.hxml b/test/regression/Issue849/build.hxml new file mode 100644 index 000000000..542c501e0 --- /dev/null +++ b/test/regression/Issue849/build.hxml @@ -0,0 +1,3 @@ +-cpp bin +-D disable-unicode-strings +-m Main diff --git a/test/regression/Issue849/stdout.txt b/test/regression/Issue849/stdout.txt new file mode 100644 index 000000000..c1214794c --- /dev/null +++ b/test/regression/Issue849/stdout.txt @@ -0,0 +1,6 @@ +Main.hx:3: Hello world +Main.hx:6: Hello world +Main.hx:9: Hello world +Main.hx:14: +Main.hx:17: +Main.hx:20: diff --git a/test/regression/Run.hx b/test/regression/Run.hx new file mode 100644 index 000000000..a233a18c7 --- /dev/null +++ b/test/regression/Run.hx @@ -0,0 +1,60 @@ +import sys.io.Process; +import sys.io.File; +import sys.FileSystem; + +using StringTools; + +function runOutput(test:String):String { + final slash = Sys.systemName() == "Windows" ? "\\" : "/"; + final proc = new Process([test, "bin", 'Main'].join(slash)); + final code = proc.exitCode(); + + if (code != 0) { + throw 'return code was $code'; + } + + return proc.stdout.readAll().toString().replace("\r\n", "\n"); +} + +function main() { + var successes = 0; + var total = 0; + + final args = Sys.args(); + + for (test in FileSystem.readDirectory(".")) { + if (!FileSystem.isDirectory(test)) { + continue; + } + + total++; + + final buildExitCode = Sys.command("haxe", ["-C", test, "build.hxml"].concat(args)); + if (buildExitCode != 0) { + Sys.println('Failed to build test $test. Exit code: $buildExitCode'); + continue; + } + + final expectedStdout = File.getContent('$test/stdout.txt').replace("\r\n", "\n"); + final actualStdout = try { + runOutput(test); + } catch (e) { + Sys.println('Test $test failed: $e'); + continue; + }; + + if (actualStdout != expectedStdout) { + Sys.println('Test $test failed: Output did not match'); + + Sys.println("Expected stdout:"); + Sys.println(expectedStdout); + Sys.println("Actual stdout:"); + Sys.println(actualStdout); + continue; + } + + successes++; + } + + Sys.println('Regression tests complete. Successes: $successes / $total'); +}