diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54a4d9f..7052a19 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -75,14 +75,14 @@ jobs: - name: Linux Tests if: contains(matrix.os, 'ubuntu') run: | - ./run_tests.sh + ./run_tests.sh --extra working-directory: tests shell: bash - name: Windows and MacOS Tests if: contains(matrix.os, 'windows') || contains(matrix.os, 'macos') run: | - ./run_tests.sh + ./run_tests.sh --extra working-directory: tests shell: bash continue-on-error: true diff --git a/ci/summary_comment.sh b/ci/summary_comment.sh index ae466e4..ab0fae2 100755 --- a/ci/summary_comment.sh +++ b/ci/summary_comment.sh @@ -34,7 +34,7 @@ echo "STAT:rough build time=${build_time}s" echo "STAT:" cd tests -./run_tests.sh --time-server +./run_tests.sh --time-server --extra echo "STAT:DCD run_tests.sh $(grep -F 'Elapsed (wall clock) time' stderr.txt)" echo "STAT:DCD run_tests.sh $(grep -F 'Maximum resident set size (kbytes)' stderr.txt)" @@ -49,7 +49,7 @@ rm -rf .dub bin/dcd-server dub build --build=profile-gc --config=server --compiler=dmd 2>&1 || echo "DCD BUILD FAILED" cd tests -./run_tests.sh +./run_tests.sh --extra echo "STAT:top 5 GC sources in server:" if [ ! -f "profilegc.log" ]; then diff --git a/makefile b/makefile index 6c5be13..74c0b57 100644 --- a/makefile +++ b/makefile @@ -137,7 +137,7 @@ ldcserver: githash ${LDC} $(LDC_SERVER_FLAGS) ${SERVER_SRC} -oq -of=bin/dcd-server test: debugserver dmdclient - cd tests && ./run_tests.sh + cd tests && ./run_tests.sh --extra release: ./release.sh diff --git a/tests/extra/tc_ufcs_all_kinds/.gitignore b/tests/extra/tc_ufcs_all_kinds/.gitignore new file mode 100644 index 0000000..6b0b58e --- /dev/null +++ b/tests/extra/tc_ufcs_all_kinds/.gitignore @@ -0,0 +1 @@ +proc_test.d diff --git a/tests/extra/tc_ufcs_all_kinds/generate_tests.d b/tests/extra/tc_ufcs_all_kinds/generate_tests.d new file mode 100644 index 0000000..637b241 --- /dev/null +++ b/tests/extra/tc_ufcs_all_kinds/generate_tests.d @@ -0,0 +1,266 @@ +// This generates functions with all specified test types as first argument + +// variables for each specified test type. +// Then it calls all functions with every type to see which ones are accepted by +// the compiler, to automatically stay up-to-date. + +import std; +import fs = std.file; + +string[] testTypes = [ + "bool", + "byte", + "ubyte", + "short", + "ushort", + "int", + "uint", + "long", + "ulong", + "char", + "wchar", + "dchar", + "float", + "double", + "real", + "BasicStruct", + "AliasThisInt", +]; +// index here must map onto varTypePermutations index +string[][] funcTypePermutations = [ + // TODO: check for const/inout/immutable/shared in UFCS checks + [ + "%s", + // "const(%s)", + "ref %s", + // "ref const(%s)" + ], + [ + "%s*", + // "const(%s)*", + // "const(%s*)", + "ref %s*", + // "ref const(%s)*", + // "ref const(%s*)" + ], + [ + "%s[]", + // "const(%s)[]", + // "const(%s[])", + "ref %s[]", + // "ref const(%s)[]", + // "ref const(%s[])" + ] +]; +string[][] varTypePermutations = [ + [ + "%s", + // "const(%s)" + ], + [ + "%s*", + // "const(%s)*", + // "const(%s*)" + ], + [ + "%s[]", + // "const(%s)[]", + // "const(%s[])" + ] +]; + +string preamble = ` +struct BasicStruct { int member1; string member2; } +struct AliasThisInt { int member1; string member2; alias member1 this; } + +`; + +int main(string[] args) +{ + string functionsCode; + string varsCode; + string callCode; + + string[] allFunctions; + string[string] funcLookup; + string[string] varLookup; + + foreach (ti, type; testTypes) + { + foreach (pi, perms; funcTypePermutations) + { + foreach (i, perm; perms) + { + string resolved = format(perm, type); + string id = getID(ti, pi, i); + allFunctions ~= ("func_" ~ id); + functionsCode ~= "void func_" ~ id ~ "(" ~ resolved ~ " arg) {}\n"; + functionsCode ~= resolved ~ " make_" ~ id ~ "() { static " ~ resolved + .chompPrefix("ref ") ~ " x; return x; }\n"; + funcLookup["func_" ~ id] = resolved; + } + } + foreach (pi, perms; varTypePermutations) + { + foreach (i, perm; perms) + { + string resolved = format(perm, type); + string id = getID(ti, pi, i); + varsCode ~= resolved ~ " var_" ~ id ~ " = make_" ~ id ~ "();\n"; + varLookup["var_" ~ id] = resolved; + foreach (cti, subType; testTypes) + foreach (ci, subPerms; funcTypePermutations) + foreach (fi, subPerm; subPerms) + { + callCode ~= "var_" ~ id ~ ".func_" ~ getID(cti, ci, fi) ~ "();\n"; + } + } + } + } + + allFunctions.sort!"a 1_000, "compiler didn't error as expected, need to adjust tests!"); + + writeln("Total incompatible type combinations: ", numErrors); + + string[][string] wrongDCDCompletions; + + foreach (varName; varLookup.byKey) + { + string input = code[0 .. $ - 2] + ~ "\n" + ~ varName ~ ".func_"; + + string[] dcdClient = ["../../../bin/dcd-client"]; + if (args[1].length) + dcdClient ~= args[1]; + + auto proc = pipeProcess(dcdClient ~ ["-c" ~ to!string(input.length)]); + proc.stdin.rawWrite(input); + proc.stdin.rawWrite("\n}\n"); + proc.stdin.close(); + + string[] dcdResult; + + size_t i = 0; + foreach (line; proc.stdout.byLineCopy) + { + if (i++ == 0) + { + enforce(line == "identifiers"); + continue; + } + + auto parts = line.split("\t"); + if (parts[1] != "F") + continue; + dcdResult ~= parts[0]; + } + + enforce(i > 0, "every variable must auto-complete something! Missing completion for var " ~ varName + ~ " of type " ~ varLookup[varName] ~ generateEmptyResponseReproductionCode( + varLookup[varName])); + enforce(dcdResult.length > 0, "Wrongly no UFCS completion for var " ~ varName + ~ " of type " ~ varLookup[varName] ~ generateEmptyResponseReproductionCode( + varLookup[varName])); + + dcdResult.sort!"a '+' ~ ln) + .chain(missingFunctions.map!(ln => '-' ~ ln)) + .array; + + // writeln(varLookup[varName], " -> ", dcdResult); + if (diff.length) + wrongDCDCompletions[varName] = diff; + } + + foreach (varName, wrongTypes; wrongDCDCompletions) + { + writeln("Incorrect results for ", varLookup[varName], ":"); + wrongTypes.sort!"a