exception/cli-error.spice
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright (c) 2021-2026 ChilliBits. All rights reserved. | ||
| 2 | |||
| 3 | // Std imports | ||
| 4 | import "std/text/stringstream"; | ||
| 5 | |||
| 6 | public type CliErrorType enum { | ||
| 7 | INCOMPATIBLE_OPTIONS, | ||
| 8 | NON_ZERO_EXIT_CODE, | ||
| 9 | FEATURE_NOT_SUPPORTED_FOR_TARGET, | ||
| 10 | FEATURE_NOT_SUPPORTED_WHEN_DOCKERIZED, | ||
| 11 | INVALID_BUILD_MODE, | ||
| 12 | INVALID_OUTPUT_CONTAINER, | ||
| 13 | INVALID_SANITIZER, | ||
| 14 | INVALID_BACKEND, | ||
| 15 | INVALID_DEBUG_INFO_LEVEL | ||
| 16 | } | ||
| 17 | |||
| 18 | /** | ||
| 19 | * Custom exception for errors, occurring when linking the output executable | ||
| 20 | */ | ||
| 21 | 9 | public type CliError struct { | |
| 22 | String errorMessage | ||
| 23 | } | ||
| 24 | |||
| 25 | /** | ||
| 26 | * @param errorType Type of the error | ||
| 27 | * @param message Error message suffix | ||
| 28 | */ | ||
| 29 | 18 | public p CliError.ctor(const CliErrorType errorType, const string message) { | |
| 30 | 18 | StringStream msg; | |
| 31 | 18 | msg << "[Error|CLI] " << this.getMessagePrefix(errorType) << ": " << message; | |
| 32 | 18 | this.errorMessage = msg.str(); | |
| 33 | 18 | } | |
| 34 | |||
| 35 | /** | ||
| 36 | * Get the message for this particular error instance | ||
| 37 | * | ||
| 38 | * @return Error message | ||
| 39 | */ | ||
| 40 | 18 | public f<const String&> CliError.getMessage() { | |
| 41 | 18 | return this.errorMessage; | |
| 42 | } | ||
| 43 | |||
| 44 | /** | ||
| 45 | * Get the prefix of the error message for a particular error | ||
| 46 | * | ||
| 47 | * @param errorType Type of the error | ||
| 48 | * @return Prefix string for the error type | ||
| 49 | */ | ||
| 50 | 18 | f<string> CliError.getMessagePrefix(const CliErrorType errorType) { | |
| 51 | 18 | switch errorType { | |
| 52 | 5 | case CliErrorType::INCOMPATIBLE_OPTIONS: { return "Incompatible options"; } | |
| 53 | 1 | case CliErrorType::NON_ZERO_EXIT_CODE: { return "Non-zero exit code"; } | |
| 54 | 1 | case CliErrorType::FEATURE_NOT_SUPPORTED_FOR_TARGET: { return "Feature is not supported for this target"; } | |
| 55 | 1 | case CliErrorType::FEATURE_NOT_SUPPORTED_WHEN_DOCKERIZED: { return "Feature not supported when dockerized"; } | |
| 56 | 2 | case CliErrorType::INVALID_BUILD_MODE: { return "Invalid build mode"; } | |
| 57 | 2 | case CliErrorType::INVALID_OUTPUT_CONTAINER: { return "Invalid output container"; } | |
| 58 | 2 | case CliErrorType::INVALID_SANITIZER: { return "Invalid sanitizer"; } | |
| 59 | 2 | case CliErrorType::INVALID_BACKEND: { return "Invalid backend"; } | |
| 60 | 2 | case CliErrorType::INVALID_DEBUG_INFO_LEVEL: { return "Invalid debug info level"; } | |
| 61 | − | default: { panic(Error("Unknown error")); } // LCOV_EXCL_LINE | |
| 62 | } | ||
| 63 | ✗ | } | |
| 64 | |||
| 65 | // ─── tests ──────────────────────────────────────────────────────────────────── | ||
| 66 | |||
| 67 | 9 | f<bool> hasMessage(const CliErrorType errorType, const string message, const string expectedMessage) { | |
| 68 | 9 | const CliError cliError = CliError(errorType, message); | |
| 69 | 18 | return cliError.getMessage() == expectedMessage; | |
| 70 | 9 | } | |
| 71 | |||
| 72 | // The driver reports cli errors by exiting the process, which a builtin test cannot observe. So the messages of the rejected cli | ||
| 73 | // arguments are checked here, at the level of the error itself | ||
| 74 | 1 | #[test] | |
| 75 | f<bool> testCliErrorMessages() { | ||
| 76 | // Invalid enum values | ||
| 77 | 1 | assert hasMessage(CliErrorType::INVALID_BUILD_MODE, "unknown", "[Error|CLI] Invalid build mode: unknown"); | |
| 78 | 1 | assert hasMessage(CliErrorType::INVALID_SANITIZER, "unknown", "[Error|CLI] Invalid sanitizer: unknown"); | |
| 79 | 1 | assert hasMessage(CliErrorType::INVALID_OUTPUT_CONTAINER, "unknown", "[Error|CLI] Invalid output container: unknown"); | |
| 80 | 1 | assert hasMessage(CliErrorType::INVALID_BACKEND, "unknown", "[Error|CLI] Invalid backend: unknown"); | |
| 81 | 1 | assert hasMessage(CliErrorType::INVALID_DEBUG_INFO_LEVEL, "unknown", "[Error|CLI] Invalid debug info level: unknown"); | |
| 82 | |||
| 83 | // Incompatible options and unsupported features | ||
| 84 | 1 | assert hasMessage(CliErrorType::INCOMPATIBLE_OPTIONS, "Cannot link statically if compiling shared library", "[Error|CLI] Incompatible options: Cannot link statically if compiling shared library"); | |
| 85 | 1 | assert hasMessage(CliErrorType::FEATURE_NOT_SUPPORTED_FOR_TARGET, "Memory sanitizer is only supported for Linux targets", "[Error|CLI] Feature is not supported for this target: Memory sanitizer is only supported for Linux targets"); | |
| 86 | 1 | assert hasMessage(CliErrorType::FEATURE_NOT_SUPPORTED_WHEN_DOCKERIZED, "message", "[Error|CLI] Feature not supported when dockerized: message"); | |
| 87 | 1 | assert hasMessage(CliErrorType::NON_ZERO_EXIT_CODE, "1", "[Error|CLI] Non-zero exit code: 1"); | |
| 88 | 1 | return true; | |
| 89 | } | ||
| 90 |