ATF_TC_BODY(oom_error_reuse, tc) { { kyua_error_t error = kyua_oom_error_new(); ATF_REQUIRE(kyua_error_is_type(error, kyua_oom_error_type)); ATF_REQUIRE(kyua_error_data(error) == NULL); kyua_error_free(error); } { kyua_error_t error = kyua_oom_error_new(); ATF_REQUIRE(kyua_error_is_type(error, kyua_oom_error_type)); ATF_REQUIRE(kyua_error_data(error) == NULL); kyua_error_free(error); } }
ATF_TC_BODY(error_format__custom__error, tc) { kyua_error_t error = kyua_error_new("test_error", NULL, 0, test_format); char buffer[5]; ATF_REQUIRE(kyua_error_format(error, buffer, sizeof(buffer)) >= (int)sizeof(buffer)); kyua_error_free(error); }
ATF_TC_BODY(error_format__default, tc) { kyua_error_t error = kyua_error_new("test_error", NULL, 0, NULL); char buffer[1024]; kyua_error_format(error, buffer, sizeof(buffer)); ATF_REQUIRE_STREQ("Error 'test_error'", buffer); kyua_error_free(error); }
ATF_TC_BODY(oom_error_format, tc) { kyua_error_t error = kyua_oom_error_new(); char buffer[1024]; kyua_error_format(error, buffer, sizeof(buffer)); ATF_REQUIRE_STREQ("Not enough memory", buffer); kyua_error_free(error); }
ATF_TC_BODY(usage_error_format__plain, tc) { kyua_error_t error = kyua_usage_error_new("Test message"); char buffer[1024]; kyua_error_format(error, buffer, sizeof(buffer)); ATF_REQUIRE_STREQ("Test message", buffer); kyua_error_free(error); }
ATF_TC_BODY(error_new__oom, tc) { void* invalid = (void*)1; kyua_error_t error = kyua_error_new("test_error", invalid, SIZE_MAX, NULL); ATF_REQUIRE(kyua_error_is_type(error, kyua_oom_error_type)); ATF_REQUIRE(kyua_error_data(error) == NULL); kyua_error_free(error); }
ATF_TC_BODY(usage_error_format__args, tc) { kyua_error_t error = kyua_usage_error_new("%s message %d", "A", 123); char buffer[1024]; kyua_error_format(error, buffer, sizeof(buffer)); ATF_REQUIRE_STREQ("A message 123", buffer); kyua_error_free(error); }
ATF_TC_BODY(error_subsume__secondary, tc) { kyua_error_t primary = kyua_error_ok(); kyua_error_t secondary = kyua_error_new("secondary_error", NULL, 0, NULL); kyua_error_t error = kyua_error_subsume(primary, secondary); ATF_REQUIRE(kyua_error_is_type(error, "secondary_error")); kyua_error_free(error); }
ATF_TC_BODY(error_is_type__not_match, tc) { kyua_error_t error = kyua_error_new("test_error", NULL, 0, NULL); ATF_REQUIRE(!kyua_error_is_type(error, "test_erro")); ATF_REQUIRE(!kyua_error_is_type(error, "test_error2")); ATF_REQUIRE(!kyua_error_is_type(error, "foo")); kyua_error_free(error); }
ATF_TC_BODY(libc_error_format__args, tc) { kyua_error_t error = kyua_libc_error_new(EPERM, "%s message %d", "A", 123); char buffer[1024]; kyua_error_format(error, buffer, sizeof(buffer)); ATF_REQUIRE(strstr(buffer, strerror(EPERM)) != NULL); ATF_REQUIRE(strstr(buffer, "A message 123") != NULL); kyua_error_free(error); }
ATF_TC_BODY(error_data__some, tc) { int data = 5; kyua_error_t error = kyua_error_new("test_data_error", &data, sizeof(data), NULL); ATF_REQUIRE(kyua_error_data(error) != NULL); ATF_REQUIRE_EQ(*((const int*)kyua_error_data(error)), 5); kyua_error_free(error); }
ATF_TC_BODY(sanitize__fail, tc) { char* sane; kyua_error_t error = kyua_fs_sanitize("non-existent/path", &sane); ATF_REQUIRE(kyua_error_is_set(error)); ATF_REQUIRE(kyua_error_is_type(error, "libc")); ATF_REQUIRE_EQ(ENOENT, kyua_libc_error_errno(error)); kyua_error_free(error); }
ATF_TC_BODY(libc_error_format__plain, tc) { kyua_error_t error = kyua_libc_error_new(ENOMEM, "Test message"); char buffer[1024]; kyua_error_format(error, buffer, sizeof(buffer)); ATF_REQUIRE(strstr(buffer, strerror(ENOMEM)) != NULL); ATF_REQUIRE(strstr(buffer, "Test message") != NULL); kyua_error_free(error); }
ATF_TC_BODY(error_format__custom__ok, tc) { kyua_error_t error = kyua_error_new("test_error", NULL, 0, test_format); const char* exp_message = "Test formatting function"; char buffer[1024]; ATF_REQUIRE_EQ((int)strlen(exp_message), kyua_error_format(error, buffer, sizeof(buffer))); ATF_REQUIRE_STREQ(exp_message, buffer); kyua_error_free(error); }
ATF_TC_BODY(fprintf, tc) { FILE* output = fopen("output", "w"); const kyua_error_t error = kyua_usage_error_new("A usage error"); kyua_error_fprintf(output, error, "The %s message", "1st"); kyua_error_free(error); fclose(output); ATF_REQUIRE(atf_utils_grep_file("The 1st message: A usage error", "output")); }
/// Looks for a core file for the given program. /// /// \param name The basename of the binary that generated the core. /// \param directory The directory from which the program was run. We expect to /// find the core file in this directory. /// \param dead_pid PID of the process that generated the core. This is needed /// in some platforms. /// /// \return The path to the core file if found; otherwise none. char* kyua_stacktrace_find_core(const char* name, const char* directory, const pid_t dead_pid) { char* candidate = NULL; // TODO(jmmv): Other than checking all these defaults, in NetBSD we should // also inspect the value of the kern.defcorename sysctl(2) MIB and use that // as the first candidate. // // In Linux, the way to determine the name is by looking at // /proc/sys/kernel/core_{pattern,uses_pid} as described by core(5). // Unfortunately, there does not seem to be a standard API to parse these // files, which makes checking for core files quite difficult if the // defaults have been modified. // Default NetBSD naming scheme. if (candidate == NULL && MAXCOMLEN > 0) { char truncated[MAXCOMLEN + 1]; candidate = try_core("%s/%s.core", directory, slice(name, truncated, sizeof(truncated))); } // Common naming scheme without the MAXCOMLEN truncation. if (candidate == NULL) candidate = try_core("%s/%s.core", directory, name); // Common naming scheme found in Linux systems. if (candidate == NULL) candidate = try_core("%s/core.%d", directory, (int)dead_pid); // Default Mac OS X naming scheme. if (candidate == NULL) candidate = try_core("/cores/core.%d", (int)dead_pid); // Common naming scheme found in Linux systems. Attempted last due to the // genericity of the core file name. if (candidate == NULL) candidate = try_core("%s/core", directory); if (candidate != NULL) { char* abs_candidate; kyua_error_t error = kyua_fs_make_absolute(candidate, &abs_candidate); if (kyua_error_is_set(error)) { kyua_error_free(error); return candidate; // Return possibly-relative path as a best guess. } else { free(candidate); return abs_candidate; } } else { return candidate; } }
ATF_TC_BODY(warn, tc) { const pid_t pid = atf_utils_fork(); if (pid == 0) { kyua_error_t error = kyua_usage_error_new("A usage error"); kyua_error_warn(error, "The %s message", "1st"); kyua_error_free(error); exit(51); } atf_utils_wait(pid, 51, "", "error_test: The 1st message: A usage error\n"); }
ATF_TC_BODY(cleanup__subdir__links, tc) { ATF_REQUIRE(mkdir("root", 0755) != -1); ATF_REQUIRE(mkdir("root/dir1", 0755) != -1); ATF_REQUIRE(symlink("../../root", "root/dir1/loop") != -1); ATF_REQUIRE(symlink("non-existent", "root/missing") != -1); ATF_REQUIRE(lookup(".", "root", DT_DIR)); kyua_error_t error = kyua_fs_cleanup("root"); if (kyua_error_is_set(error)) { if (lchmod_fails()) atf_tc_expect_fail("lchmod(2) is not implemented in your system"); kyua_error_free(error); atf_tc_fail("kyua_fs_cleanup returned an error"); } ATF_REQUIRE(!lookup(".", "root", DT_DIR)); }
ATF_TC_BODY(fgets_error__libc_error, tc) { atf_utils_create_file("test.txt", "Some line\n"); char buffer[1024]; FILE* input = fopen("test.txt", "w"); ATF_REQUIRE(kyua_text_fgets_no_newline(buffer, sizeof(buffer), input) == NULL); kyua_error_t error = kyua_text_fgets_error(input, "Foo bar"); ATF_REQUIRE(kyua_error_is_set(error)); kyua_error_format(error, buffer, sizeof(buffer)); ATF_REQUIRE_MATCH("^Foo bar: .*", buffer); kyua_error_free(error); fclose(input); }
ATF_TC_BODY(work_directory__permissions_error, tc) { char* tmpdir; RE(kyua_fs_make_absolute("worktest", &tmpdir)); ATF_REQUIRE(mkdir(tmpdir, 0755) != -1); RE(kyua_env_set("TMPDIR", tmpdir)); char* work_directory; const kyua_error_t error = kyua_run_work_directory_enter( "template.XXXXXX", getuid() + 1, getgid(), &work_directory); ATF_REQUIRE(kyua_error_is_set(error)); ATF_REQUIRE(kyua_error_is_type(error, "libc")); ATF_REQUIRE_EQ(EPERM, kyua_libc_error_errno(error)); kyua_error_free(error); ATF_REQUIRE(rmdir(tmpdir) != -1); // Empty; subdirectory not created. free(tmpdir); }
ATF_TC_BODY(current_path__enoent, tc) { char* previous; ATF_REQUIRE(!kyua_error_is_set(kyua_fs_current_path(&previous))); ATF_REQUIRE(mkdir("root", 0755) != -1); ATF_REQUIRE(chdir("root") != -1); ATF_REQUIRE(rmdir("../root") != -1); char* cwd = (char*)0xdeadbeef; kyua_error_t error = kyua_fs_current_path(&cwd); ATF_REQUIRE(kyua_error_is_set(error)); ATF_REQUIRE(kyua_error_is_type(error, "libc")); ATF_REQUIRE_EQ(ENOENT, kyua_libc_error_errno(error)); ATF_REQUIRE_EQ((char*)0xdeadbeef, cwd); kyua_error_free(error); free(previous); }
ATF_TC_BODY(fgets_error__unexpected_eof, tc) { atf_utils_create_file("test.txt", "Some line\n"); char buffer[1024]; FILE* input = fopen("test.txt", "r"); ATF_REQUIRE(kyua_text_fgets_no_newline(buffer, sizeof(buffer), input) == buffer); ATF_REQUIRE_STREQ("Some line", buffer); ATF_REQUIRE(kyua_text_fgets_no_newline(buffer, sizeof(buffer), input) == NULL); kyua_error_t error = kyua_text_fgets_error(input, "Foo bar"); ATF_REQUIRE(kyua_error_is_set(error)); kyua_error_format(error, buffer, sizeof(buffer)); ATF_REQUIRE_STREQ("Foo bar: unexpected EOF", buffer); kyua_error_free(error); fclose(input); }
/// Generates a path and checks if it exists. /// /// \param format Formatting string for the path to generate. /// \param ... Arguments to the formatting string. /// /// \return A dynamically-allocated string containing the generated path if /// there were no errors and the file pointed to by such path exists; NULL /// otherwise. The returned string must be relesed with free() by the caller. static char* try_core(const char* format, ...) { char* path; va_list ap; va_start(ap, format); kyua_error_t error = kyua_text_vprintf(&path, format, ap); va_end(ap); if (kyua_error_is_set(error)) { // Something went really wrong (and should not have happened). Ignore // this core file candidate. kyua_error_free(error); return NULL; } if (access(path, F_OK) == -1) { free(path); return NULL; } else { return path; } }
/// Writes a generic result file based on an ATF result file and an exit code. /// /// \param input_name Path to the ATF result file to parse. /// \param output_name Path to the generic result file to create. /// \param wait_status Exit code of the test program as returned by wait(). /// \param timed_out Whether the test program timed out or not. /// \param [out] success Whether the result should be considered a success or /// not; e.g. passed and skipped are successful, but failed is not. /// /// \return An error if the conversion fails; OK otherwise. kyua_error_t kyua_atf_result_rewrite(const char* input_name, const char* output_name, const int wait_status, const bool timed_out, bool* success) { enum atf_status status; int status_arg; char reason[1024]; status = ATF_STATUS_BROKEN; // Initialize to shut up gcc warning. const kyua_error_t error = read_atf_result(input_name, &status, &status_arg, reason, sizeof(reason)); if (kyua_error_is_set(error)) { // Errors while parsing the ATF result file can often be attributed to // the result file being bogus. Therefore, just mark the test case as // broken, because it possibly is. status = ATF_STATUS_BROKEN; kyua_error_format(error, reason, sizeof(reason)); kyua_error_free(error); } // Errors converting the loaded result to the final result file are not due // to a bad test program: they are because our own code fails (e.g. cannot // create the output file). These need to be returned to the caller. return convert_result(status, status_arg, reason, wait_status, timed_out, output_name, success); }
ATF_TC_BODY(usage_error_type, tc) { kyua_error_t error = kyua_usage_error_new("Nothing"); ATF_REQUIRE(kyua_error_is_type(error, kyua_usage_error_type)); kyua_error_free(error); }
ATF_TC_BODY(error_is_set__yes, tc) { kyua_error_t error = kyua_error_new("test_error", NULL, 0, NULL); ATF_REQUIRE(kyua_error_is_set(error)); kyua_error_free(error); }
ATF_TC_BODY(oom_error_data, tc) { kyua_error_t error = kyua_oom_error_new(); ATF_REQUIRE(kyua_error_data(error) == NULL); kyua_error_free(error); }
ATF_TC_BODY(oom_error_type, tc) { kyua_error_t error = kyua_oom_error_new(); ATF_REQUIRE(kyua_error_is_type(error, kyua_oom_error_type)); kyua_error_free(error); }
ATF_TC_BODY(libc_error_type, tc) { kyua_error_t error = kyua_libc_error_new(ENOMEM, "Nothing"); ATF_REQUIRE(kyua_error_is_type(error, kyua_libc_error_type)); kyua_error_free(error); }
ATF_TC_BODY(libc_error_errno, tc) { kyua_error_t error = kyua_libc_error_new(EPERM, "Doesn't matter"); ATF_REQUIRE_EQ(EPERM, kyua_libc_error_errno(error)); kyua_error_free(error); }