Customizing I/O of CoverageScanner library
Custom I/O using C file access
The following example shows how to generate the execution report using the standard C file API.
To compile the example on Microsoft® Windows:
cscl customiofile.c
To compile the example on Linux™ or macOS:
csgcc customiofile.c -o customiofile
Source code:
#include <stdio.h> #include <string.h> #define VERBOSE 1 static int csfputs(const char *s, void *stream) { #if VERBOSE fprintf(stderr, "csfputs:%s\n", s); #endif return fputs(s, (FILE *)stream); } static void *csfopenappend(const char *path) { #if VERBOSE fprintf(stderr, "csfopenappend:%s\n", path); #endif return (void *)fopen(path, "a+"); } static void *csfopenread(const char *path) { #if VERBOSE fprintf(stderr, "csfopenread:%s\n", path); #endif return (void *)fopen(path, "r"); } static void *csfopenwrite(const char *path) { #if VERBOSE fprintf(stderr, "csfopenwrite:%s\n", path); #endif return (void *)fopen(path, "w"); } static char *csfgets(char *s, int size, void *stream) { char *ret; ret = fgets(s, size, (FILE *)stream); #if VERBOSE fprintf(stderr, "csfgets:%s\n", s); #endif return ret; } static int csremove(const char *path) { #if VERBOSE fprintf(stderr, "csremove:%s\n", path); #endif return remove(path); } static int csfclose(void *stream) { #if VERBOSE fprintf(stderr, "csfclose\n"); #endif return fclose((FILE *)stream); } int main(int argc, char* argv[]) { char location[256]; int lg_location; printf(".csexe file name (without extension}:"); fflush(stdout); fgets(location, sizeof(location), stdin); lg_location = strlen(location); if (lg_location) location[lg_location - 1] = '\0'; // strip \n #ifdef __COVERAGESCANNER__ __coveragescanner_set_custom_io(csfgets, csfputs, csfopenappend, csfopenread, csfopenwrite, csfclose, csremove); __coveragescanner_install(location); #endif }
Custom I/O using a UNix TCP/IP server
The following example shows how to generate the execution report using the standard Unix socket API. The application intergrates then a TCP/IP server that permits to send the code coderage counters through the local network.
The simple socat
command can be used to fetch the data. For example:
$ socat -dd - TCP4:localhost:4321 > app.csexe
This command retrieves from localhost on the port 4321 the code coverage and store it into the file app.csexe
. This can then be imported using cmcsexeimport
:
$ socat -dd - TCP4:localhost:4321 > app.csexe && cmcsexeimport -m app.csmes -t test –delete app.csexe
CoverageBrowser supports also supports the possibility to integrate this command into the import dialog. This permits to do interactive manual tests on which CoverageBrowser fetches and imports the coverage data after pressing on the "Load Execution Report" button.
For this, just select the Script
mode and enter the command socat -dd - TCP4:localhost:4321
. Deactivate the Delete execution report after loading
because it requires a specific command to delete remotely a .csexe
file.
Clicking on Next
permits to display a terminal window which permits to follow the progress.
This view switches automatically to the final import dialog on success:
The server code need to be integrated into the target application. To do it, it is necessary to compile coverage.c
and activate the server. For this, it is necessary to place the following code snippet at the beginning of the program:
#ifdef __COVERAGESCANNER__ start_coverage_server( 4321 ); #endif
The number passed on start_coverage_server()
function is the TCP port number to server.
To compile the example on Linux™ or macOS:
csgcc coverage.c -o coverage.o csgcc app.c -o app.o csgcc app.o cooverage.o -o app.exe
Source code of the application sample:
#include "coverage.h" #include <time.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main() { #ifdef __COVERAGESCANNER__ start_coverage_server( 4321 ); #endif srand( time(NULL) ); static char *banner = "Hello,\n" "please use the following command to dump the code coverage:\n" "$ socat -dd - TCP4:<IP address from this computer>:4321\n" ; int line = 1; while ( 1 ) { char *c = banner; fprintf( stderr, "%4i: ", line ); line++; while ( *c != '\0' ) { fputc( *c, stderr ); if ( *c == '\n' ) { fprintf( stderr, "%4i: ", line ); line++; } c++; usleep( rand()%200000 ); } fputc( '\n', stderr ); sleep( 1 ); } return 0; }
Source code of the server code:
#ifndef COVERAGE_H #define COVERAGE_H #ifdef __COVERAGESCANNER__ void start_coverage_server( int port ); #endif #endif
#ifdef __COVERAGESCANNER__ #include "coverage.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netinet/in.h> #include <pthread.h> typedef struct { int conn ; } cov_ctx_t; static int csfputs(const char *s, void *stream) { ssize_t ret; cov_ctx_t *ctx = (cov_ctx_t*)stream; ret = write( ctx->conn, s, strlen(s) ); if ( ret < 0 ) perror( "TCP writing error" ); return (int)ret; } static void *csfopenappend(const char *s) { cov_ctx_t *ctx = (cov_ctx_t*)malloc( sizeof(cov_ctx_t) ); ctx->conn = atoi( s ); return (void *)ctx; } static int csfclose(void *stream) { cov_ctx_t *ctx = (cov_ctx_t*)stream; close(ctx->conn); free(ctx); return 1; } static void coverage_server( int port ) { int clintListn = 0, clintConnt = 0; struct sockaddr_in ipOfServer; clintListn = socket(AF_INET, SOCK_STREAM, 0); memset(&ipOfServer, '0', sizeof(ipOfServer)); ipOfServer.sin_family = AF_INET; ipOfServer.sin_addr.s_addr = htonl(INADDR_ANY); ipOfServer.sin_port = htons( port ); bind(clintListn, (struct sockaddr*)&ipOfServer , sizeof(ipOfServer)); listen(clintListn , 20); __coveragescanner_set_custom_io(NULL, csfputs, csfopenappend, NULL, NULL, csfclose, NULL); while(1) { clintConnt = accept(clintListn, (struct sockaddr*)NULL, NULL); static char location[20]; sprintf( location, "%i", clintConnt ); __coveragescanner_filename( location ); __coveragescanner_save(); } } static void* coverage_thread( void *port_p ) { int port = *(int*)port_p; coverage_server( port ); } void start_coverage_server( int port ) { static int p ; p = port; pthread_t thread; pthread_create( &thread, NULL, coverage_thread, &p ); } #endif
Custom I/O using SFTP protocol
The following example shows how to generate the execution report directly on a SFTP server. The SFTP server is part of SSH v2 and is available on most Unix platforms. On Windows, a free SSH server can be downloaded from freeSSHd and freeFTPd.
To compile the example on Windows:
- Download libSSH2 from libssh2. Build the library, and set the environment variable
LIBSSH2
to the build/install location - To compile the example:
cscl %LIBSSH2%\win32\debug_dll\libssh2.lib -DWIN32 --cs-libgen=/MTd /MTd -I %LIBSSH2%\include ws2_32.lib customiosftp.c
- Execute
custom_io_sftp.exe
.
To compile the example on Linux™:
- Install the development package of libssh2.
- To compile the example:
csgcc -lssh2 customiosftp.c -o customiosftp
- Execute
custom_io_sftp
.
Source code:
#define VERBOSE 1 #ifdef WIN32 #include <winsock2.h> #define LIBSSH2_WIN32 #define LIBSSH2_API #else #include <arpa/inet.h> #include <netinet/in.h> #include <sys/socket.h> #include <unistd.h> #endif #include <libssh2.h> #include <libssh2_sftp.h> #include <ctype.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <sys/types.h> static LIBSSH2_SESSION *session = NULL; static LIBSSH2_SFTP *sftp_session = NULL; static int sock = 0; static void extract_location(const char *location, char *server, char *user, char *passwd, char *file) { int i, j; int lg_location; lg_location = strlen(location); for (i = 0; i < lg_location; i++) { if (location[i] == '\n') break; server[i] = location[i]; } server[i] = '\0'; i++; for (j = 0; i < lg_location; i++, j++) { if (location[i] == '\n') break; user[j] = location[i]; } user[j] = '\0'; i++; for (j = 0; i < lg_location; i++, j++) { if (location[i] == '\n') break; passwd[j] = location[i]; } passwd[j] = '\0'; i++; for (j = 0; i < lg_location; i++, j++) { if (location[i] == '\0') break; file[j] = location[i]; } file[j] = '\0'; } static void close_sftp_session() { if (sftp_session) libssh2_sftp_shutdown(sftp_session); sftp_session = NULL; if (session) { libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing"); libssh2_session_free(session); } session = NULL; if (sock) { #ifdef WIN32 Sleep(1000); closesocket(sock); #else sleep(1); close(sock); #endif } sock = 0; } static int open_sftp_session(const char *server, const char *user, const char *passwd) { struct sockaddr_in sin; int rc; sock = socket(AF_INET, SOCK_STREAM, 0); sin.sin_family = AF_INET; sin.sin_port = htons(22); sin.sin_addr.s_addr = inet_addr(server); if (connect(sock, (struct sockaddr *)(&sin), sizeof(struct sockaddr_in)) != 0) { close_sftp_session(); return 0; } /* Create a session instance */ session = libssh2_session_init(); if (!session) { close_sftp_session(); return 0; } /* ... start it up. This will trade welcome banners, exchange keys, * and setup crypto, compression, and MAC layers */ rc = libssh2_session_startup(session, sock); if (rc) { close_sftp_session(); return 0; } libssh2_session_set_blocking(session, 1); if (libssh2_userauth_password(session, user, passwd)) { close_sftp_session(); return 0; } sftp_session = libssh2_sftp_init(session); if (!sftp_session) { close_sftp_session(); return 0; } return 1; } static int csfputs(const char *s, void *stream) { #if VERBOSE fprintf(stderr, "csfputs:%s\n", s); #endif return libssh2_sftp_write((LIBSSH2_SFTP_HANDLE *)stream, s, strlen(s)); } static void *csfopenappend(const char *location) { LIBSSH2_SFTP_HANDLE *handle; char server[1024]; char user[1024]; char passwd[1024]; char file[1024]; LIBSSH2_SFTP_ATTRIBUTES attrs; extract_location(location, server, user, passwd, file); #if VERBOSE fprintf(stderr, "csfopenappend %s:%s:%s\n", server, user, file); #endif if (open_sftp_session(server, user, passwd)) { handle = libssh2_sftp_open( sftp_session, file, LIBSSH2_FXF_CREAT | LIBSSH2_FXF_WRITE, LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IROTH); } else return NULL; if (handle) { if (libssh2_sftp_fstat(handle, &attrs) == 0) { /* Go to the end of the file */ libssh2_sftp_seek(handle, attrs.filesize); } } return handle; } static void *csfopenread(const char *location) { char server[1024]; char user[1024]; char passwd[1024]; char file[1024]; extract_location(location, server, user, passwd, file); #if VERBOSE fprintf(stderr, "csfopenread %s:%s:%s\n", server, user, file); #endif if (open_sftp_session(server, user, passwd)) return (void *)libssh2_sftp_open(sftp_session, file, LIBSSH2_FXF_READ, 0); else return NULL; } static void *csfopenwrite(const char *location) { char server[1024]; char user[1024]; char passwd[1024]; char file[1024]; extract_location(location, server, user, passwd, file); #if VERBOSE fprintf(stderr, "csfopenwrite %s:%s:%s\n", server, user, file); #endif if (open_sftp_session(server, user, passwd)) return (void *)libssh2_sftp_open( sftp_session, file, LIBSSH2_FXF_CREAT | LIBSSH2_FXF_WRITE, LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IROTH); else return NULL; } static char *csfgets(char *s, int size, void *stream) { size_t ss; ss = libssh2_sftp_read((LIBSSH2_SFTP_HANDLE *)stream, s, size - 1); if (ss) { s[ss] = '\0'; #if VERBOSE fprintf(stderr, "csfgets:%s\n", s); #endif return s; } else return NULL; } static int csremove(const char *location) { int ret; char server[1024]; char user[1024]; char passwd[1024]; char file[1024]; extract_location(location, server, user, passwd, file); #if VERBOSE fprintf(stderr, "csremove %s:%s:%s\n", server, user, file); #endif if (open_sftp_session(server, user, passwd)) { ret = libssh2_sftp_unlink(sftp_session, file); close_sftp_session(); return ret; } else return -1; } static int csfclose(void *fp) { #if VERBOSE fprintf(stderr, "csfclose\n"); #endif return libssh2_sftp_close((LIBSSH2_SFTP_HANDLE *)fp); } int main() { char location[1024]; char tmp[1024]; #ifdef WIN32 WSADATA wsadata; WSAStartup(WINSOCK_VERSION, &wsadata); #endif location[0] = '\0'; printf("server IP:"); fflush(stdout); fgets(tmp, sizeof(tmp), stdin); strcat(location, tmp); printf("user:"); fflush(stdout); fgets(tmp, sizeof(tmp), stdin); strcat(location, tmp); printf("passwd:"); fflush(stdout); fgets(tmp, sizeof(tmp), stdin); strcat(location, tmp); printf(".csexe file name (without extension}:"); fflush(stdout); fgets(tmp, sizeof(tmp), stdin); strcat(location, tmp); location[strlen(location) - 1] = '\0'; #ifdef __COVERAGESCANNER__ __coveragescanner_set_custom_io(csfgets, csfputs, csfopenappend, csfopenread, csfopenwrite, csfclose, csremove); __coveragescanner_install(location); #endif }
Coco v7.2.1 ©2024 The Qt Company Ltd.
Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property
of their respective owners.