Participer au site avec un Tip
Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Les pointeurs sur fonctions en C

Manipulation de listes chaînées Les mots clés static, extern, ...


Le langage C permet de manipuler des pointeurs sur fonctions. A titre d'exemple, voici un mini système d'exécution de batteries de tests unitaire. Pour définir le contenu d'une batterie de tests, des pointeurs sur fonctions sont utilisés : ces fonctions doivent bien entendu respecter une signature bien précise, cette signature étant décrite dans le type de pointeurs sur fonctions TestFunction.

Ce premier fichier de code correspond à un exemple d'utilisation du framework de test. Notez que chaque fonctions de tests doit renvoyer un booléen : la valeur true signifie que le test s'est exécuté en succès et une valeur false signifie, au contraire, que le test a échoué.

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

#include "TestFramework.h"

bool test1( const char * testName ) {
    // TODO
    return true;
}

bool test2( const char * testName ) {
    // TODO
    return false;
}

// TODO ...

int main() {

    TestFramework tester;
    addTestFunction( &tester, "Nom du premier test", test1 );
    addTestFunction( &tester, "Nom de second test", test2 );
    runTestSuite( &tester );

    // Résultat de l'exécution du programme :
    // Run "Nom du premier test"        Ok
    // Run "Nom de second test"         Ko
    // -----------------------
    // Run 2 tests
    //      1 test in success
    //      1 test in failure

    return EXIT_SUCCESS;
}
Fichier main.c

Le second fichier correspond au fichier d'entête de définition du framework de test. Il est notamment inclu par le fichier main.c.

#ifndef TESTFRAMEWORK_H_
#define TESTFRAMEWORK_H_

#include <stdbool.h>
#include <stddef.h>

/* Defines a new typedef based on a function pointeur type. */
typedef bool (* TestFunction)( const char * );

typedef struct _ListNode {
    const char * testName;
    TestFunction fct;
    struct _ListNode * next;
} ListNode;

typedef struct {
    ListNode * first;
} List;


List createEmptyList();
void insertList( List * list, const char * testName, TestFunction fct );
void displayList( List * list );
void destroyList( List * list );


typedef struct {
    List functions;
} TestFramework;

//void addTestFunction( TestFramework * framework, const char * testName, bool (*fct)( const char * ) );
void addTestFunction( TestFramework * framework, const char * testName, TestFunction fct );
void runTestSuite( TestFramework * framework );


#endif /* TESTFRAMEWORK_H_ */
Fichier TestFramework.h

Enfin, voici l'implémentation de notre framework de test.

#include <assert.h>
#include <stdio.h>

#include "TestFramework.h"


List createEmptyList() {
    List emptyList;
    emptyList.first = NULL;
    return emptyList;
}

/**
 * Caution: in our sample, the list must be ordered.
 */
void insertList( List * list, const char * testName, TestFunction fct ) {
    ListNode * toInsert = (ListNode *) malloc( sizeof( ListNode ) );

    if ( list->first == NULL ) {
        list->first = toInsert;
        toInsert->testName = testName;
        toInsert->fct = fct;
        toInsert->next = NULL;
        return;
    }

    ListNode * current = list->first;
    while ( true ) {
        int compareResult = strcmp( testName, current->testName );
        if ( compareResult < 0 ) {
            toInsert->testName = current->testName;
            toInsert->fct = current->fct;
            toInsert->next = current->next;

            current->testName = testName;
            current->fct = fct;
            current->next = toInsert;
            return;
        }
        if ( current->next == NULL ) {
            current->next = toInsert;
            toInsert->testName = testName;
            toInsert->fct = fct;
            toInsert->next = NULL;
            return;
        }

        current = current->next;
    }
}


void displayList( List * list ) {
    ListNode * current = list->first;
    while( current != NULL ) {
        printf( "\"%s\" -> ", current->testName );
        current = current->next;
    }
    puts( "NULL\n" );
}

void destroyList( List * list ) {
    ListNode * current = list->first;
    while( current != NULL ) {
        ListNode * next = current->next;
        free( current );
        current = next;
    }
    list->first = NULL;
}


static bool testFrameworkIsInitialized = false;

void addTestFunction( TestFramework * framework, const char * testName, TestFunction fct ) {
    if ( ! testFrameworkIsInitialized ) {
        framework->functions = createEmptyList();
        testFrameworkIsInitialized = true;
    }

    insertList( &framework->functions, testName, fct );
}

void runTestSuite( TestFramework * framework ) {
    size_t goodTests = 0;
    size_t badTests = 0;

    ListNode * current = framework->functions.first;
    while( current != NULL ) {
        const char * testName = current->testName;
        bool result = current->fct( testName );
        if ( result ) goodTests++; else badTests++;
        printf( "Run %-30s %s\n", testName, result ? "Ok" : "Ko" );

        current = current->next;
    }

    printf( "----------------------------------------------\n" );
    printf( "Run %lu test(s)\n", goodTests+badTests );
    printf( "\t%lu test(s) in success\n", goodTests );
    printf( "\t%lu test(s) in failure\n", badTests );

    destroyList( &framework->functions );
}
Fichier TestFramework.c
Manipulation de listes chaînées Les mots clés static, extern, ...