From 632342b25437335e820c1ee3eb4de466948c4c28 Mon Sep 17 00:00:00 2001 From: Rangi <35663410+Rangi42@users.noreply.github.com> Date: Sun, 16 Feb 2025 19:56:55 +0100 Subject: [PATCH] Use `LCOV_EXCL` comments to exclude some lines from test coverage (#1662) --- .gitignore | 1 + include/asm/symbol.hpp | 1 - include/either.hpp | 2 +- src/asm/fstack.cpp | 6 +- src/asm/lexer.cpp | 29 +++++++-- src/asm/main.cpp | 14 +++- src/asm/output.cpp | 22 +++---- src/asm/rpn.cpp | 61 ++---------------- src/asm/section.cpp | 4 ++ src/asm/symbol.cpp | 22 +++---- src/fix/main.cpp | 4 ++ src/gfx/main.cpp | 6 ++ src/link/main.cpp | 6 ++ test/asm/break.asm | 11 ++++ test/asm/break.err | 6 +- test/asm/invalid-utf-8-strings.asm | 5 +- test/asm/invalid-utf-8-strings.err | 8 ++- test/asm/invalid-utf-8-strings.out | 1 + test/asm/macro-arg-escape-chars.asm | Bin 79 -> 66 bytes test/asm/macro-arg-escape-chars.out | Bin 22 -> 10 bytes test/asm/macro-arg-illegal-escape.asm | 5 ++ ...chars.err => macro-arg-illegal-escape.err} | 4 +- test/asm/macro-arg-illegal-escape.out | 1 + test/asm/raw-string-symbols.asm | 5 +- test/asm/raw-string-symbols.out.bin | Bin 19 -> 39 bytes test/asm/unterminated-if-eof.asm | 2 + test/asm/unterminated-if-eof.err | 2 + test/gfx/test.sh | 4 ++ test/gfx/write_stdout.bin | Bin 0 -> 127 bytes test/gfx/write_stdout.out.2bpp | 1 + 30 files changed, 133 insertions(+), 100 deletions(-) create mode 100644 test/asm/macro-arg-illegal-escape.asm rename test/asm/{macro-arg-escape-chars.err => macro-arg-illegal-escape.err} (58%) create mode 100644 test/asm/macro-arg-illegal-escape.out create mode 100644 test/asm/unterminated-if-eof.asm create mode 100644 test/asm/unterminated-if-eof.err create mode 100644 test/gfx/write_stdout.bin create mode 100644 test/gfx/write_stdout.out.2bpp diff --git a/.gitignore b/.gitignore index 58b81825..fdb7c9f8 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ CMakeCache.txt CMakeFiles/ cmake_install.cmake build/ +*.dSYM/ callgrind.out.* diff --git a/include/asm/symbol.hpp b/include/asm/symbol.hpp index fc27e6b8..4730bf5f 100644 --- a/include/asm/symbol.hpp +++ b/include/asm/symbol.hpp @@ -82,7 +82,6 @@ Symbol *sym_RedefEqu(std::string const &symName, int32_t value); Symbol *sym_AddVar(std::string const &symName, int32_t value); int32_t sym_GetRSValue(); void sym_SetRSValue(int32_t value); -uint32_t sym_GetConstantValue(std::string const &symName); // Find a symbol by exact name, bypassing expansion checks Symbol *sym_FindExactSymbol(std::string const &symName); // Find a symbol, possibly scoped, by name diff --git a/include/either.hpp b/include/either.hpp index 06634c12..eb2cac15 100644 --- a/include/either.hpp +++ b/include/either.hpp @@ -103,7 +103,7 @@ public: } else if (other._tag == other._t2.tag_value) { *this = other._t2.value; } else { - _tag = nulltag; + _tag = nulltag; // LCOV_EXCL_LINE } return *this; } diff --git a/src/asm/fstack.cpp b/src/asm/fstack.cpp index 87bb8589..40d396ec 100644 --- a/src/asm/fstack.cpp +++ b/src/asm/fstack.cpp @@ -119,9 +119,11 @@ void fstk_SetPreIncludeFile(std::string const &path) { warnx("Overriding pre-included filename %s", preIncludeName.c_str()); } preIncludeName = path; + // LCOV_EXCL_START if (verbose) { printf("Pre-included filename %s\n", preIncludeName.c_str()); } + // LCOV_EXCL_STOP } static void printDep(std::string const &path) { @@ -308,9 +310,11 @@ void fstk_RunInclude(std::string const &path, bool preInclude) { if (!fullPath) { if (generatedMissingIncludes && !preInclude) { + // LCOV_EXCL_START if (verbose) { printf("Aborting (-MG) on INCLUDE file '%s' (%s)\n", path.c_str(), strerror(errno)); } + // LCOV_EXCL_STOP failedOnMissingInclude = true; } else { error("Unable to open included file '%s': %s\n", path.c_str(), strerror(errno)); @@ -319,7 +323,7 @@ void fstk_RunInclude(std::string const &path, bool preInclude) { } if (!newFileContext(*fullPath, false)) { - fatalerror("Failed to set up lexer for file include\n"); + fatalerror("Failed to set up lexer for file include\n"); // LCOV_EXCL_LINE } } diff --git a/src/asm/lexer.cpp b/src/asm/lexer.cpp index d981c596..d7423701 100644 --- a/src/asm/lexer.cpp +++ b/src/asm/lexer.cpp @@ -77,6 +77,7 @@ struct FileUnmapDeleter { static char *mapFile(int fd, std::string const &path, size_t size) { void *mappingAddr = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0); + // LCOV_EXCL_START if (mappingAddr == MAP_FAILED && errno == ENOTSUP) { // The implementation may not support MAP_PRIVATE; try again with MAP_SHARED // instead, offering, I believe, weaker guarantees about external modifications to @@ -86,6 +87,7 @@ static char *mapFile(int fd, std::string const &path, size_t size) { } mappingAddr = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0); } + // LCOV_EXCL_STOP return mappingAddr != MAP_FAILED ? static_cast(mappingAddr) : nullptr; } @@ -412,21 +414,27 @@ bool LexerState::setFileAsNextState(std::string const &filePath, bool updateStat if (filePath == "-") { path = ""; content.emplace(STDIN_FILENO); + // LCOV_EXCL_START if (verbose) { printf("Opening stdin\n"); } + // LCOV_EXCL_STOP } else { struct stat statBuf; if (stat(filePath.c_str(), &statBuf) != 0) { + // LCOV_EXCL_START error("Failed to stat file \"%s\": %s\n", filePath.c_str(), strerror(errno)); return false; + // LCOV_EXCL_STOP } path = filePath; int fd = open(path.c_str(), O_RDONLY); if (fd < 0) { + // LCOV_EXCL_START error("Failed to open file \"%s\": %s\n", path.c_str(), strerror(errno)); return false; + // LCOV_EXCL_STOP } bool isMmapped = false; @@ -438,9 +446,11 @@ bool LexerState::setFileAsNextState(std::string const &filePath, bool updateStat content.emplace( std::shared_ptr(mappingAddr, FileUnmapDeleter(size)), size ); + // LCOV_EXCL_START if (verbose) { printf("File \"%s\" is mmap()ped\n", path.c_str()); } + // LCOV_EXCL_STOP isMmapped = true; } } @@ -448,6 +458,7 @@ bool LexerState::setFileAsNextState(std::string const &filePath, bool updateStat if (!isMmapped) { // Sometimes mmap() fails or isn't available, so have a fallback content.emplace(fd); + // LCOV_EXCL_START if (verbose) { if (statBuf.st_size == 0) { printf("File \"%s\" is empty\n", path.c_str()); @@ -457,6 +468,7 @@ bool LexerState::setFileAsNextState(std::string const &filePath, bool updateStat ); } } + // LCOV_EXCL_STOP } } @@ -552,7 +564,9 @@ size_t BufferedContent::readMore(size_t startIndex, size_t nbChars) { ssize_t nbReadChars = read(fd, &buf[startIndex], nbChars); if (nbReadChars == -1) { + // LCOV_EXCL_START fatalerror("Error while reading \"%s\": %s\n", lexerState->path.c_str(), strerror(errno)); + // LCOV_EXCL_STOP } size += nbReadChars; @@ -761,7 +775,9 @@ int LexerState::peekCharAhead() { // and `.peekCharAhead()` will continue with its parent assume(exp.offset <= exp.size()); if (exp.offset + distance < exp.size()) { - return static_cast((*exp.contents)[exp.offset + distance]); + // Macro args can't be recursive, since `peek()` marks them as scanned, so + // this is a failsafe that (as far as I can tell) won't ever actually run. + return static_cast((*exp.contents)[exp.offset + distance]); // LCOV_EXCL_LINE } distance -= exp.size() - exp.offset; } @@ -1323,8 +1339,11 @@ static void appendEscapedString(std::string &str, std::string const &escape) { str += "\\n"; break; case '\r': + // A literal CR in a string may get treated as a LF, so '\r' is not tested. + // LCOV_EXCL_START str += "\\r"; break; + // LCOV_EXCL_STOP case '\t': str += "\\t"; break; @@ -2163,7 +2182,8 @@ static Token skipIfBlock(bool toEndc) { case T_(POP_ELIF): if (lexer_ReachedELSEBlock()) { - fatalerror("Found ELIF after an ELSE block\n"); + // This should be redundant, as the parser handles this error first. + fatalerror("Found ELIF after an ELSE block\n"); // LCOV_EXCL_LINE } if (!toEndc && lexer_GetIFDepth() == startingDepth) { return token; @@ -2255,9 +2275,8 @@ static Token yylex_SKIP_TO_ENDR() { case T_(POP_ENDR): depth--; - if (!depth) { - return Token(T_(YYEOF)); // yywrap() will finish the REPT/FOR loop - } + // `lexer_CaptureRept` has already guaranteed that the `ENDR`s are balanced + assume(depth > 0); break; case T_(POP_IF): diff --git a/src/asm/main.cpp b/src/asm/main.cpp index 2da5e28a..38703fcf 100644 --- a/src/asm/main.cpp +++ b/src/asm/main.cpp @@ -87,6 +87,7 @@ static option const longopts[] = { {nullptr, no_argument, nullptr, 0 } }; +// LCOV_EXCL_START static void printUsage() { fputs( "Usage: rgbasm [-EhVvw] [-b chars] [-D name[=value]] [-g chars] [-I path]\n" @@ -107,6 +108,7 @@ static void printUsage() { stderr ); } +// LCOV_EXCL_STOP int main(int argc, char *argv[]) { time_t now = time(nullptr); @@ -176,8 +178,10 @@ int main(int argc, char *argv[]) { break; case 'h': + // LCOV_EXCL_START printUsage(); exit(0); + // LCOV_EXCL_STOP case 'I': fstk_AddIncludePath(musl_optarg); @@ -195,7 +199,7 @@ int main(int argc, char *argv[]) { dependFileName = ""; } if (dependFile == nullptr) { - err("Failed to open dependfile \"%s\"", dependFileName); + err("Failed to open dependfile \"%s\"", dependFileName); // LCOV_EXCL_LINE } break; @@ -302,9 +306,11 @@ int main(int argc, char *argv[]) { if (stateFileSpecs.find(name) != stateFileSpecs.end()) { warnx("Overriding state filename %s", name); } + // LCOV_EXCL_START if (verbose) { printf("State filename %s\n", name); } + // LCOV_EXCL_STOP stateFileSpecs.emplace(name, std::move(features)); break; } @@ -314,8 +320,10 @@ int main(int argc, char *argv[]) { exit(0); case 'v': + // LCOV_EXCL_START verbose = true; break; + // LCOV_EXCL_STOP case 'W': opt_W(musl_optarg); @@ -367,8 +375,10 @@ int main(int argc, char *argv[]) { // Unrecognized options default: + // LCOV_EXCL_START printUsage(); exit(1); + // LCOV_EXCL_STOP } } @@ -391,7 +401,7 @@ int main(int argc, char *argv[]) { std::string mainFileName = argv[musl_optind]; if (verbose) { - printf("Assembling %s\n", mainFileName.c_str()); + printf("Assembling %s\n", mainFileName.c_str()); // LCOV_EXCL_LINE } if (dependFile) { diff --git a/src/asm/output.cpp b/src/asm/output.cpp index e65b03f0..699f5539 100644 --- a/src/asm/output.cpp +++ b/src/asm/output.cpp @@ -61,7 +61,7 @@ void out_RegisterNode(std::shared_ptr node) { } } -// Return a section's ID, or UINT32_MAX if the section is not in the list +// Return a section's ID, or UINT32_MAX if the section does not exist static uint32_t getSectIDIfAny(Section *sect) { if (!sect) { return UINT32_MAX; @@ -71,7 +71,8 @@ static uint32_t getSectIDIfAny(Section *sect) { return static_cast(search->second); } - fatalerror("Unknown section '%s'\n", sect->name.c_str()); + // Every section that exists should be in `sectionMap` + fatalerror("Unknown section '%s'\n", sect->name.c_str()); // LCOV_EXCL_LINE } static void writePatch(Patch const &patch, FILE *file) { @@ -175,7 +176,7 @@ static void writeRpn(std::vector &rpnexpr, std::vector const & sym = sym_FindExactSymbol(symName); if (sym->isConstant()) { rpnexpr[rpnptr++] = RPN_CONST; - value = sym_GetConstantValue(symName); + value = sym->getConstantValue(); } else { rpnexpr[rpnptr++] = RPN_SYM; registerUnregisteredSymbol(*sym); // Ensure that `sym->ID` is set @@ -323,7 +324,7 @@ void out_WriteObject() { file = stdout; } if (!file) { - err("Failed to open object file '%s'", objectFileName.c_str()); + err("Failed to open object file '%s'", objectFileName.c_str()); // LCOV_EXCL_LINE } Defer closeFile{[&] { fclose(file); }}; @@ -343,14 +344,7 @@ void out_WriteObject() { writeFileStackNode(node, file); // The list is supposed to have decrementing IDs - if (it + 1 != fileStackNodes.end() && it[1]->ID != node.ID - 1) { - fatalerror( - "Internal error: fstack node #%" PRIu32 " follows #%" PRIu32 - ". Please report this to the developers!\n", - it[1]->ID, - node.ID - ); - } + assume(it + 1 == fileStackNodes.end() || it[1]->ID == node.ID - 1); } for (Symbol const *sym : objectSymbols) { @@ -373,9 +367,11 @@ void out_SetFileName(std::string const &name) { warnx("Overriding output filename %s", objectFileName.c_str()); } objectFileName = name; + // LCOV_EXCL_START if (verbose) { printf("Output filename %s\n", objectFileName.c_str()); } + // LCOV_EXCL_STOP } static void dumpString(std::string const &escape, FILE *file) { @@ -528,7 +524,7 @@ void out_WriteState(std::string name, std::vector const &features) file = stdout; } if (!file) { - err("Failed to open state file '%s'", name.c_str()); + err("Failed to open state file '%s'", name.c_str()); // LCOV_EXCL_LINE } Defer closeFile{[&] { fclose(file); }}; diff --git a/src/asm/rpn.cpp b/src/asm/rpn.cpp index aaee3a83..36009431 100644 --- a/src/asm/rpn.cpp +++ b/src/asm/rpn.cpp @@ -94,7 +94,7 @@ void Expression::makeSymbol(std::string const &symName) { *ptr++ = RPN_SYM; memcpy(ptr, sym->name.c_str(), nameLen); } else { - data = static_cast(sym_GetConstantValue(symName)); + data = static_cast(sym->getConstantValue()); } } @@ -325,42 +325,12 @@ void Expression::makeUnaryOp(RPNCommand op, Expression &&src) { case RPN_TZCOUNT: data = val != 0 ? ctz(uval) : 32; break; - - case RPN_LOGOR: - case RPN_LOGAND: - case RPN_LOGEQ: - case RPN_LOGGT: - case RPN_LOGLT: - case RPN_LOGGE: - case RPN_LOGLE: - case RPN_LOGNE: - case RPN_ADD: - case RPN_SUB: - case RPN_XOR: - case RPN_OR: - case RPN_AND: - case RPN_SHL: - case RPN_SHR: - case RPN_USHR: - case RPN_MUL: - case RPN_DIV: - case RPN_MOD: - case RPN_EXP: - case RPN_BANK_SYM: - case RPN_BANK_SECT: - case RPN_BANK_SELF: - case RPN_SIZEOF_SECT: - case RPN_STARTOF_SECT: - case RPN_SIZEOF_SECTTYPE: - case RPN_STARTOF_SECTTYPE: - case RPN_HRAM: - case RPN_RST: - case RPN_BIT_INDEX: - case RPN_CONST: - case RPN_SYM: + default: // `makeUnaryOp` should never be called with a non-unary operator! + // LCOV_EXCL_START unreachable_(); } + // LCOV_EXCL_STOP } else if (op == RPN_LOGNOT && tryConstLogNot(src)) { data = 0; } else if (int32_t constVal; op == RPN_LOW && (constVal = tryConstLow(src)) != -1) { @@ -503,29 +473,12 @@ void Expression::makeBinaryOp(RPNCommand op, Expression &&src1, Expression const data = op_exponent(lval, rval); break; - - case RPN_NEG: - case RPN_NOT: - case RPN_LOGNOT: - case RPN_BANK_SYM: - case RPN_BANK_SECT: - case RPN_BANK_SELF: - case RPN_SIZEOF_SECT: - case RPN_STARTOF_SECT: - case RPN_SIZEOF_SECTTYPE: - case RPN_STARTOF_SECTTYPE: - case RPN_HRAM: - case RPN_RST: - case RPN_BIT_INDEX: - case RPN_HIGH: - case RPN_LOW: - case RPN_BITWIDTH: - case RPN_TZCOUNT: - case RPN_CONST: - case RPN_SYM: + default: // `makeBinaryOp` should never be called with a non-binary operator! + // LCOV_EXCL_START unreachable_(); } + // LCOV_EXCL_STOP } else if (op == RPN_SUB && src1.isDiffConstant(src2.symbolOf())) { data = src1.symbolOf()->getValue() - src2.symbolOf()->getValue(); } else if ((op == RPN_LOGAND || op == RPN_AND) && tryConstZero(src1, src2)) { diff --git a/src/asm/section.cpp b/src/asm/section.cpp index 6415c7af..7faa60be 100644 --- a/src/asm/section.cpp +++ b/src/asm/section.cpp @@ -875,9 +875,11 @@ void sect_BinaryFile(std::string const &name, int32_t startPos) { } if (!file) { if (generatedMissingIncludes) { + // LCOV_EXCL_START if (verbose) { printf("Aborting (-MG) on INCBIN file '%s' (%s)\n", name.c_str(), strerror(errno)); } + // LCOV_EXCL_STOP failedOnMissingInclude = true; } else { error("Error opening INCBIN file '%s': %s\n", name.c_str(), strerror(errno)); @@ -942,9 +944,11 @@ void sect_BinaryFileSlice(std::string const &name, int32_t startPos, int32_t len } if (!file) { if (generatedMissingIncludes) { + // LCOV_EXCL_START if (verbose) { printf("Aborting (-MG) on INCBIN file '%s' (%s)\n", name.c_str(), strerror(errno)); } + // LCOV_EXCL_STOP failedOnMissingInclude = true; } else { error("Error opening INCBIN file '%s': %s\n", name.c_str(), strerror(errno)); diff --git a/src/asm/symbol.cpp b/src/asm/symbol.cpp index 47b022db..53159dea 100644 --- a/src/asm/symbol.cpp +++ b/src/asm/symbol.cpp @@ -325,19 +325,6 @@ uint32_t Symbol::getConstantValue() const { return 0; } -uint32_t sym_GetConstantValue(std::string const &symName) { - if (Symbol const *sym = sym_FindScopedSymbol(symName); sym) { - return sym->getConstantValue(); - } - - if (sym_IsPurgedScoped(symName)) { - error("'%s' not defined; it was purged\n", symName.c_str()); - } else { - error("'%s' not defined\n", symName.c_str()); - } - return 0; -} - std::pair sym_GetCurrentLabelScopes() { return {globalScope, localScope}; } @@ -528,8 +515,10 @@ static uint32_t anonLabelID = 0; Symbol *sym_AddAnonLabel() { if (anonLabelID == UINT32_MAX) { + // LCOV_EXCL_START error("Only %" PRIu32 " anonymous labels can be created!", anonLabelID); return nullptr; + // LCOV_EXCL_STOP } std::string anon = sym_MakeAnonLabelName(0, true); // The direction is important! @@ -555,6 +544,7 @@ std::string sym_MakeAnonLabelName(uint32_t ofs, bool neg) { } else { ofs--; // We're referencing symbols that haven't been created yet... if (ofs > UINT32_MAX - anonLabelID) { + // LCOV_EXCL_START error( "Reference to anonymous label %" PRIu32 " after, when only %" PRIu32 " may still be created\n", @@ -562,6 +552,7 @@ std::string sym_MakeAnonLabelName(uint32_t ofs, bool neg) { UINT32_MAX - anonLabelID ); } else { + // LCOV_EXCL_STOP id = anonLabelID + ofs; } } @@ -571,8 +562,11 @@ std::string sym_MakeAnonLabelName(uint32_t ofs, bool neg) { void sym_Export(std::string const &symName) { if (symName.starts_with('!')) { + // LCOV_EXCL_START + // The parser does not accept anonymous labels for an `EXPORT` directive error("Anonymous labels cannot be exported\n"); return; + // LCOV_EXCL_STOP } Symbol *sym = sym_FindScopedSymbol(symName); @@ -654,11 +648,13 @@ void sym_Init(time_t now) { sym_AddEqu("__RGBDS_RC__"s, PACKAGE_VERSION_RC)->isBuiltin = true; #endif + // LCOV_EXCL_START if (now == static_cast(-1)) { warn("Failed to determine current time"); // Fall back by pretending we are at the Epoch now = 0; } + // LCOV_EXCL_STOP tm const *time_local = localtime(&now); diff --git a/src/fix/main.cpp b/src/fix/main.cpp index 070fc885..53d9c836 100644 --- a/src/fix/main.cpp +++ b/src/fix/main.cpp @@ -54,6 +54,7 @@ static option const longopts[] = { {nullptr, no_argument, nullptr, 0 } }; +// LCOV_EXCL_START static void printUsage() { fputs( "Usage: rgbfix [-hjOsVv] [-C | -c] [-f ] [-i ] [-k ]\n" @@ -72,6 +73,7 @@ static void printUsage() { stderr ); } +// LCOV_EXCL_STOP static uint8_t nbErrors; @@ -1322,8 +1324,10 @@ int main(int argc, char *argv[]) { break; case 'h': + // LCOV_EXCL_START printUsage(); exit(0); + // LCOV_EXCL_STOP case 'i': gameID = musl_optarg; diff --git a/src/gfx/main.cpp b/src/gfx/main.cpp index 2498097b..09cdd793 100644 --- a/src/gfx/main.cpp +++ b/src/gfx/main.cpp @@ -156,6 +156,7 @@ static option const longopts[] = { {nullptr, no_argument, nullptr, 0 } }; +// LCOV_EXCL_START static void printUsage() { fputs( "Usage: rgbgfx [-r stride] [-ChmOuVXYZ] [-v [-v ...]] [-a | -A]\n" @@ -174,6 +175,7 @@ static void printUsage() { stderr ); } +// LCOV_EXCL_STOP // Parses a number at the beginning of a string, moving the pointer to skip the parsed characters. // Returns the provided errVal on error. @@ -425,8 +427,10 @@ static char *parseArgv(int argc, char *argv[]) { } break; case 'h': + // LCOV_EXCL_START printUsage(); exit(0); + // LCOV_EXCL_STOP case 'i': if (!options.inputTileset.empty()) { warning("Overriding input tileset file %s", options.inputTileset.c_str()); @@ -615,8 +619,10 @@ static char *parseArgv(int argc, char *argv[]) { } break; default: + // LCOV_EXCL_START printUsage(); exit(1); + // LCOV_EXCL_STOP } } diff --git a/src/link/main.cpp b/src/link/main.cpp index 0fd54eca..79852761 100644 --- a/src/link/main.cpp +++ b/src/link/main.cpp @@ -163,6 +163,7 @@ static option const longopts[] = { {nullptr, no_argument, nullptr, 0 } }; +// LCOV_EXCL_START static void printUsage() { fputs( "Usage: rgblink [-dhMtVvwx] [-l script] [-m map_file] [-n sym_file]\n" @@ -181,6 +182,7 @@ static void printUsage() { stderr ); } +// LCOV_EXCL_STOP enum ScrambledRegion { SCRAMBLE_ROMX, @@ -335,8 +337,10 @@ int main(int argc, char *argv[]) { isWRAM0Mode = true; break; case 'h': + // LCOV_EXCL_START printUsage(); exit(0); + // LCOV_EXCL_STOP case 'l': if (linkerScriptName) { warnx("Overriding linker script %s", linkerScriptName); @@ -407,8 +411,10 @@ int main(int argc, char *argv[]) { is32kMode = true; break; default: + // LCOV_EXCL_START printUsage(); exit(1); + // LCOV_EXCL_STOP } } diff --git a/test/asm/break.asm b/test/asm/break.asm index d93b422a..c6429959 100644 --- a/test/asm/break.asm +++ b/test/asm/break.asm @@ -7,6 +7,17 @@ FOR V, 1, 100 PRINTLN "cont" ENDR WARN "done {d:V}" +rept 2 + break + ; skips nested code + rept 3 + println "\tinner" + endr + if 1 + println "\tconditional" + endc + println "outer" +endr rept 1 break ; skips invalid code diff --git a/test/asm/break.err b/test/asm/break.err index e9a961a8..797c7955 100644 --- a/test/asm/break.err +++ b/test/asm/break.err @@ -1,8 +1,8 @@ warning: break.asm(9): [-Wuser] done 5 -warning: break.asm(17): [-Wuser] +warning: break.asm(28): [-Wuser] OK -error: break.asm(18): +error: break.asm(29): BREAK can only be used inside a REPT/FOR block -FATAL: break.asm(19) -> break.asm::REPT~1(23): +FATAL: break.asm(30) -> break.asm::REPT~1(34): Ended block with 1 unterminated IF construct diff --git a/test/asm/invalid-utf-8-strings.asm b/test/asm/invalid-utf-8-strings.asm index 0404f639..7e6bfee3 100644 --- a/test/asm/invalid-utf-8-strings.asm +++ b/test/asm/invalid-utf-8-strings.asm @@ -19,7 +19,7 @@ DEF copy EQUS STRSUB("{invalid}", 1) println "\"{#s:invalid}\" == \"{#s:copy}\" ({d:n})" DEF mid1 EQUS STRSUB("{invalid}", 5, 2) -DEF mid2 EQUS STRSUB("{invalid}", 9, 1) +DEF mid2 EQUS STRSLICE("{invalid}", 8, 9) println "\"{#s:mid2}{#s:mid1}\"" ; characters: @@ -53,3 +53,6 @@ println "\"{#s:invalid}\": {d:n} == {d:r}" DEF final EQUS STRSUB("{invalid}", 4, 1) println "\"{#s:invalid}\" ends \"{#s:final}\"" + +REDEF final EQUS STRSLICE("{invalid}", 3, 4) +println "\"{#s:invalid}\" ends \"{#s:final}\"" diff --git a/test/asm/invalid-utf-8-strings.err b/test/asm/invalid-utf-8-strings.err index e15422c2..6cf13848 100644 --- a/test/asm/invalid-utf-8-strings.err +++ b/test/asm/invalid-utf-8-strings.err @@ -15,9 +15,9 @@ error: invalid-utf-8-strings.asm(17): error: invalid-utf-8-strings.asm(17): STRSUB: Invalid UTF-8 byte 0xA2 error: invalid-utf-8-strings.asm(22): - STRSUB: Invalid UTF-8 byte 0xA3 + STRSLICE: Invalid UTF-8 byte 0xA3 error: invalid-utf-8-strings.asm(22): - STRSUB: Invalid UTF-8 byte 0xA4 + STRSLICE: Invalid UTF-8 byte 0xA4 error: invalid-utf-8-strings.asm(35): STRLEN: Invalid UTF-8 byte 0xFE error: invalid-utf-8-strings.asm(35): @@ -56,4 +56,6 @@ error: invalid-utf-8-strings.asm(50): STRLEN: Incomplete UTF-8 character error: invalid-utf-8-strings.asm(54): STRSUB: Incomplete UTF-8 character -error: Assembly aborted (29 errors)! +error: invalid-utf-8-strings.asm(57): + STRSLICE: Incomplete UTF-8 character +error: Assembly aborted (30 errors)! diff --git a/test/asm/invalid-utf-8-strings.out b/test/asm/invalid-utf-8-strings.out index 5602df61..c8c5c274 100644 --- a/test/asm/invalid-utf-8-strings.out +++ b/test/asm/invalid-utf-8-strings.out @@ -4,3 +4,4 @@ "漢" "abc": 4 == 4 "abc" ends "" +"abc" ends "" diff --git a/test/asm/macro-arg-escape-chars.asm b/test/asm/macro-arg-escape-chars.asm index 08e2eb123bda90b429b3df6afcd54d12f0f8f4b9..c3fdbdf36a9a32d944c5f75704b7fff2c2079d21 100644 GIT binary patch literal 66 zcmeZubPn=YNXyUX;w&i2%qz*sQ;0F-a`kiZNAj;^HhQ%FHXt$x~3ORxY+Gu2tf4^>gv% h0;*MriHT8)DTyhHF^I{Fsg9|Q(TUNB(TpjN0RU~H7ghiO diff --git a/test/asm/macro-arg-escape-chars.out b/test/asm/macro-arg-escape-chars.out index 84b5a2636bd61aae57ceeea79b37862b5786f4ce..d4f3fc9e9eb13dcf5f5fafaee74b5a6ed090dc1b 100644 GIT binary patch literal 10 RcmY#VQsQLbQc_al0ssX~0O|k$ literal 22 dcma!viBXCvi7ARPh{=nouGP`dERTud0svOh2Q>fy diff --git a/test/asm/macro-arg-illegal-escape.asm b/test/asm/macro-arg-illegal-escape.asm new file mode 100644 index 00000000..08e2eb12 --- /dev/null +++ b/test/asm/macro-arg-illegal-escape.asm @@ -0,0 +1,5 @@ +MACRO mac + DEF s EQUS "\#" + println "{#s:s}" +ENDM +mac \\\"\t\r\0\n\{\}\,\(\)\w\ \ No newline at end of file diff --git a/test/asm/macro-arg-escape-chars.err b/test/asm/macro-arg-illegal-escape.err similarity index 58% rename from test/asm/macro-arg-escape-chars.err rename to test/asm/macro-arg-illegal-escape.err index 06d9d2a6..c7ca0196 100644 --- a/test/asm/macro-arg-escape-chars.err +++ b/test/asm/macro-arg-illegal-escape.err @@ -1,5 +1,5 @@ -error: macro-arg-escape-chars.asm(5): +error: macro-arg-illegal-escape.asm(5): Illegal character escape 'w' -error: macro-arg-escape-chars.asm(5): +error: macro-arg-illegal-escape.asm(5): Illegal character escape at end of input error: Assembly aborted (2 errors)! diff --git a/test/asm/macro-arg-illegal-escape.out b/test/asm/macro-arg-illegal-escape.out new file mode 100644 index 00000000..84b5a263 --- /dev/null +++ b/test/asm/macro-arg-illegal-escape.out @@ -0,0 +1 @@ +\\\"\t\r\0\n\{},()w\\ diff --git a/test/asm/raw-string-symbols.asm b/test/asm/raw-string-symbols.asm index 3f08cb72..e49bd53d 100644 --- a/test/asm/raw-string-symbols.asm +++ b/test/asm/raw-string-symbols.asm @@ -28,7 +28,10 @@ purge #name assert !def(name) && !def(#name) && def(hello) section "test", rom0 -#label: + db #hello dw #hello +dl #hello + +#label: dw BANK(#label), #label diff --git a/test/asm/raw-string-symbols.out.bin b/test/asm/raw-string-symbols.out.bin index ad0d52e2eeaa13f70f1f17cdd2453acebf0690fc..7d154d204d71e9dcf4c6b6c2d4f7c1f5b113a15c 100644 GIT binary patch literal 39 mcmXTVFUmrQ1 diff --git a/test/asm/unterminated-if-eof.asm b/test/asm/unterminated-if-eof.asm new file mode 100644 index 00000000..5bbfc652 --- /dev/null +++ b/test/asm/unterminated-if-eof.asm @@ -0,0 +1,2 @@ +if 0 +; no newline at end of file \ No newline at end of file diff --git a/test/asm/unterminated-if-eof.err b/test/asm/unterminated-if-eof.err new file mode 100644 index 00000000..2a6bca11 --- /dev/null +++ b/test/asm/unterminated-if-eof.err @@ -0,0 +1,2 @@ +FATAL: unterminated-if-eof.asm(2): + Ended block with 1 unterminated IF construct diff --git a/test/gfx/test.sh b/test/gfx/test.sh index 7896b630..c8937e76 100755 --- a/test/gfx/test.sh +++ b/test/gfx/test.sh @@ -109,6 +109,10 @@ for f in *.[12]bpp; do runTest && tryCmp "$f" result.2bpp || failTest $? done +# Test writing to stdout +newTest "$RGBGFX -m -o - write_stdout.bin > result.2bpp" +runTest && tryCmp write_stdout.out.2bpp result.2bpp || failTest $? + if [[ "$failed" -eq 0 ]]; then echo "${bold}${green}All ${tests} tests passed!${rescolors}${resbold}" else diff --git a/test/gfx/write_stdout.bin b/test/gfx/write_stdout.bin new file mode 100644 index 0000000000000000000000000000000000000000..fea3f14fd29b72a591b5801bdb882a055e3f58a9 GIT binary patch literal 127 zcmeAS@N?(olHy`uVBq!ia0vp^0wBx;Bp3=bcE|uJH%}MGkcwN$Kk6HP+8>r*EBcLR ze%RVq=@whFt|oCTJi0Z3wfWd0Jzlo8p{v6jI^X|qbjf(Z)fOClxZzb;nr>SLvowPd Z7sI8Ss+t;t&nAIP_H^}gS?83{1ORi}Dv|&I literal 0 HcmV?d00001 diff --git a/test/gfx/write_stdout.out.2bpp b/test/gfx/write_stdout.out.2bpp new file mode 100644 index 00000000..ecad0534 --- /dev/null +++ b/test/gfx/write_stdout.out.2bpp @@ -0,0 +1 @@ +? @@xG~A? ~ \ No newline at end of file