[GO] Lassen Sie uns etwas entwickeln, das mit TDD ~ libevdev Initialisierungs- / Beendigungsverarbeitung ~ nahezu eingebettet ist

Einführung

Mit googletest / googlemock entwickle ich Software, die unter Embedded Linux mit TDD läuft. Da die mit TDD tatsächlich entwickelte Prozedur so geschrieben ist, wie sie in Echtzeit ist, gibt es einen zufälligen Teil. Ich hoffe, Sie genießen den Prozess auch. Wenn Sie Fragen oder Fehler haben, kommentieren Sie bitte. Es wird ermutigend sein.

Wenn Sie mehr über die bisherige Geschichte erfahren möchten, lesen Sie bitte die vorherigen Artikel. Versuchen Sie, mit TDD ~ Preparation ~ etwas zu entwickeln, das nahezu eingebettet ist Versuchen Sie, etwas zu entwickeln, das mit TDD nahezu eingebettet ist ~ Problemauslösung ~ Versuchen Sie, mit TDD ~ file open ~ etwas zu entwickeln, das nahezu eingebettet ist

libevdev-Initialisierung

Initialisierungserfolgstest

Betrachten Sie nun einen Test, um libevdev zu initialisieren. Es wäre schön, wenn die Initialisierungsfunktion von libevdev zusätzlich zu der zuletzt erstellten open () aufgerufen würde.

TEST_F(KeyInputEventTest, CanInitEvdev) {
  const int kFd = 3;
  //Mock ist IO_OPEN()Dateideskriptor in"3"Gib es zurück
  EXPECT_CALL(*mock_io, IO_OPEN(_, _)).WillOnce(Return(kFd));
  //Erwartete Werte für das neu hinzugefügte libevdev-Modell
  EXPECT_CALL(*mock_libevdev, libevdev_new_from_fd(kFd, _))
    .WillOnece(Return(0));

  EXPECT_TRUE(InitKeyInputDevice("./test_event"));
}

In diesem EXPECT_CALL () erwarten wir, dass der geöffnete Dateideskriptor an das erste Argument von libevdev_new_from_fd () übergeben wird ("_" bedeutet, dass das Argument egal ist). Der Mock testet, ob die Funktion mit den angegebenen Argumenten aufgerufen wurde.

Wie von TDD versprochen, wird dieser Test nicht einmal kompiliert. Lassen Sie uns zuerst ein Modell erstellen, damit es kompiliert werden kann.

Der Header enthält die echte libevdev.h, um kleinere Fehler wie Rechtschreibfehler zu vermeiden.

#include <gmock/gmock.h>
//Dieser Header ist echt
#include <libevdev/libevdev.h>

class MOCK_LIBEVDEV {
 public:
    MOCK_METHOD2(libevdev_new_from_fd, int(int, libevdev**));
};

extern MOCK_LIBEVDEV *mock_libevdev;

extern "C" {
  //Produktcode ist libevdev_new_from_fd()Diese Funktion wird beim Aufruf aufgerufen
  //Mock heißt darin.
  int libevdev_new_from_fd(int fd, libevdev **dev)
  {
    return mock_libevdev->libevdev_new_from_fd(fd, dev);
  }
}

Wenn Sie das Modell implementieren, wird es kompiliert. Achten Sie im Test darauf, nicht die reale Bibliothek zu verknüpfen, sondern den Mock zu verknüpfen. Selbst wenn die Kompilierung erfolgreich ist, schlägt der Test fehl, da er nicht den erwarteten Wert für den Aufruf von libevdev_new_from_fd () in Init () erfüllt.

[ RUN      ] KeyInputEventTest.CanInitEvdev
led_controller/test/key_input_event_test.cpp:76: Failure
Actual function call count doesn't match EXPECT_CALL(*mock_libevdev, libevdev_new_from_fd(kFd, _))...
         Expected: to be called once
           Actual: never called - unsatisfied and active
[  FAILED  ] KeyInputEventTest.CanInitEvdev (0 ms)

Fügen Sie Init () die folgenden zwei Zeilen hinzu, und der Test ist erfolgreich.

  struct libevdev *evdev = NULL;
  libevdev_new_from_fd(fd, &evdev);

Initialisierungsfehler

Betrachten wir nun einen Test, wenn ein libevdev-Initialisierungsfehler auftritt. In der libevdev-Dokumentation scheint libevdev_new_from_fd () bei Erfolg 0 und ansonsten einen negativen Fehlercode zurückzugeben. (In EXPECT_CALL (), das ich zuvor hinzugefügt habe, wurde der Rückgabewert von libevdev_new_from_fd () auf 0 gesetzt, da ich diese Spezifikation kannte.) Der mögliche Fehlercode kann nicht aus dem Dokument gelesen werden.

libevdev libevdev_new_from_fd()

Werfen wir einen Blick auf den Komponententest, der mit dem libevdev-Quellcode geliefert wird, um festzustellen, welcher Fehlercode zurückgegeben wird.

[libevdev github mirror] (https://github.com/whot/libevdev/blob/master/test/test-libevdev-init.c)

Ich habe nach einem Test gesucht.

START_TEST(test_init_from_invalid_fd)
{
	int rc;
	struct libevdev *dev = NULL;

	rc = libevdev_new_from_fd(-1, &dev);

	ck_assert(dev == NULL);
	ck_assert_int_eq(rc, -EBADF);

	rc = libevdev_new_from_fd(STDIN_FILENO, &dev);
	ck_assert(dev == NULL);
	ck_assert_int_eq(rc, -ENOTTY);
}
END_TEST

Es scheint, dass EBADF zurückgegeben wird, wenn fd an libevdev -1 ist, und ENOTTY zurückgegeben wird, wenn fd die Standardeingabe ist. Es können keine anderen Testfälle für einen Fehler gefunden werden. Es ist intuitiv, aber es fühlt sich seltsam an, dass kein anderer Fehler zurückgegeben wird. Sehen Sie sich den Quellcode an. ENOMEM aufgrund eines Speicherzuordnungsfehlers, ENOENT, wenn kein Gerät vorhanden ist, EBADF, wenn die zur Initialisierung übergebene libevdev-Struktur bereits initialisiert wurde, und andere Situationen, in denen errno zurückgegeben wird, scheinen diese errno zurückzugeben. Wenn Sie interessiert sind, lesen Sie bitte den Code unten.

github libevdev.c

Bisher scheint es keinen Fehler zu geben, der besondere Aufmerksamkeit erfordert. Wenn libevdev_new_from_fd () eine negative Zahl zurückgibt, gibt Init () false zurück. Der Test war wie folgt. Das Argument für libevdev_new_from_fd () interessiert mich nicht, also ist es mir egal.

TEST_F(KeyInputEventTest, InitEvdevFailed) {
  EXPECT_CALL(*mock_libevdev, libevdev_new_from_fd(_, _))
    .WillOnce(Return(-EBADF));  //EBADF als Vertreter. Wenn Sie sich besonders für die Strenge interessieren, können Sie den Grenzwert testen.

  EXPECT_FALSE(InitKeyInputDevice("./test_event"));
}

Fügen Sie die folgenden zwei Zeilen hinzu, um einen Produktcode zu erhalten, der diesen Test erfüllt:

  int rc = libevdev_new_from_fd(fd, &evdev);
  if (rc < 0) return false;

Wenn Sie den Code so schreiben, gibt googlemock die folgende Warnung aus. Dies ist der normale Betrieb von googlemock und es gibt kein Problem sowohl mit dem Testcode als auch mit dem Produktcode.

[ RUN      ] KeyInputEventTest.InitEvdevFailed

GMOCK WARNING:
Uninteresting mock function call - returning default value.
    Function call: IO_OPEN(0x4e6015 pointing to "./test_event", 2048)
          Returns: 0
NOTE: You can safely ignore the above warning unless this call should not happen.  Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call.  See https://github.com/google/googletest/blob/master/googlemock/docs/CookBook.md#knowing-when-to-expect for details.
[       OK ] KeyInputEventTest.InitEvdevFailed (0 ms)

Die Ursache für den Warnungstext ist, dass beim Aufruf von Init () IO_OPEN () aufgerufen wird, der erwartete Wert jedoch nicht geschrieben wird. Wie Sie in der Warnung sehen können, ist dieser Test nicht daran interessiert, IO_OPEN () aufzurufen, und kann sicher ignoriert werden. Wenn Sie debuggen möchten, können Sie die Ausgabe dieser Warnung einschränken, indem Sie beim Ausführen des Tests die folgenden Optionen angeben. --gmock_verbose=error Die Warnung sollte jedoch ordnungsgemäß gelesen werden, um sicherzustellen, dass Sie keinen unbeabsichtigten Anruf tätigen.

Fehler von libevdev_new_from_fd () behandelt (kann übersprungen werden)

libevdev_new_from_fd () scheint nicht in der Lage zu sein, zu verstehen, warum das Öffnen der Datei fehlgeschlagen ist. Unabhängig davon, ob der Fehler beim Öffnen der Datei "Berechtigung verweigert" oder "Keine solche Datei oder kein solches Verzeichnis" lautet, wird er als fehlerhafter Dateideskriptor behandelt.

Als Test habe ich den folgenden Test geschrieben und ihn ohne Root-Rechte ausgeführt. Der Versuch, ein Ereignisgerät ohne Root-Rechte zu öffnen, führt zu einem Fehler, bei dem die Berechtigung verweigert wurde. Daher wurde der von libevdev_new_from_fd () zurückgegebene erwartete Wert auf -EACCES festgelegt.

TEST_F(EvdevSampleOpenTest, TestEvdevError) {
  struct libevdev *dev {nullptr};
  int fd = open("/dev/input/event2", O_RDONLY|O_NONBLOCK);
  int rc = libevdev_new_from_fd(fd, &dev);

  EXPECT_EQ(-EACCES, rc);
}

Das Ergebnis schlägt wie folgt fehl.

[ RUN      ] EvdevSampleOpenTest.TestEvdevError
/home/tomoyuki/work/02.TDD/TDDforEmbeddedSystem/evdev_test/test/evdev_sample_test.cpp:46: Failure
Expected equality of these values:
  -13
  rc
    Which is: -9
[  FAILED  ] EvdevSampleOpenTest.TestEvdevError (0 ms)

Ich wollte, dass es -EACCES (-13) ist, aber es war tatsächlich ein fehlerhafter Dateideskriptorfehler, nämlich -EBADF (-9).

libevdev-Beendigungsprozess

Es gibt Zeiten, in denen der Endverarbeitungstest nicht gut funktioniert. Schreiben wir es sowohl auf das Kaninchen als auch auf die Ecke.

TEST_F(KeyInputEventTest, CleanupKeyInputDevice) {
  EXPECT_TRUE(CleanupKeyInputDevice());
}

Was gibt Cleanup () für true zurück? Kann es falsch zurückgeben? Beeilen Sie sich nicht, überprüfen Sie die Spezifikationen von libevdev und schließen Sie.

libevdev libevdev_free()

void libevdev_free(struct libevdev *dev)	

Insbesondere ist es unwahrscheinlich, dass ein Fehler zurückgegeben wird. Ich habe jedoch Informationen gefunden, die in Zukunft nützlich sein könnten.

After completion, the struct libevdev is invalid and must not be used.

Das heißt, ein Funktionsaufruf, der libevdev nach dem Aufruf von Cleanup () verwendet, sollte fehlschlagen. Fügen Sie es der ToDo-Liste hinzu.

Dann Manpage zum Schließen.

close () gibt bei Erfolg 0 zurück. Wenn ein Fehler auftritt, geben Sie -1 zurück und setzen Sie errno entsprechend. EBADF fd ist kein gültiger offener Deskriptor. Der EINTR-Aufruf close () wurde durch ein Signal unterbrochen. Siehe Signal (7). Ein EIO-E / A-Fehler ist aufgetreten.

EBADF wird wahrscheinlich auftreten. Es ist ein Muster, das ein nicht geöffneter Deskriptor zum Schließen übergibt. Ein Test, der libevdev erfolgreich beendet, sieht folgendermaßen aus:

TEST_F(KeyInputEventTest, CanCleanupKeyInputDevice) {
  InitKeyInputDevice(kFilePath);
  EXPECT_TRUE(CleanupKeyInputDevice());
}

Im aktuellen Produktcode sind fd und libevdev in Init () als lokale Variablen definiert. Das von Cleanup () zu verarbeitende Ziel ist nicht bekannt. Teilen Sie daher fd und libevdev mit Init (). Sammeln Sie die erforderlichen Daten in einer Struktur und definieren Sie sie im Dateibereich. Initialisieren wir es mit einem explizit ungültigen Dateideskriptor.

typedef struct {
  int fd;
  struct libevdev *evdev;
} KeyInputDeviceStruct;

enum {INVALID_FD = -1};
static KeyInputDeviceStruct dev = {INVALID_FD, NULL};

// Init()Initialisiert die Mitgliedsvariablen von dev.
bool InitKeyInputDevice(const char *device_file) {
  dev.fd = IO_OPEN(device_file, O_RDONLY|O_NONBLOCK);
  if (dev.fd < 0) {
  ...
}

wie wär es damit? Es scheint kein besonderes Problem zu geben. Lassen Sie uns Cleanup () implementieren. Der Code wird weggelassen, aber der erforderliche Mock wird ebenfalls implementiert.

bool CleanupKeyInputDevice() {
  libevdev_free(dev.evdev);  //Nennen Sie den Mock im Test
  int rc = IO_CLOSE(dev.fd);  //Nennen Sie den Mock im Test
  if (rc < 0) return false;  //Sie können zunächst ohne diese Zeile implementieren

  return true;
}

Der eigentliche Test zum Testen des obigen Codes sieht folgendermaßen aus: (Eigentlich habe ich den Test zuerst geschrieben)

//Ich habe einen Helfer für Init vorbereitet, weil er in Zukunft verwendet zu werden scheint.
static void InitHelper(const char *path, int fd, int res_evdev_new) {
  EXPECT_CALL(*mock_io, IO_OPEN(path, _)).WillOnce(Return(fd));
  EXPECT_CALL(*mock_libevdev, libevdev_new_from_fd(fd, _))
    .WillOnce(Return(res_evdev_new));

  InitKeyInputDevice(path);
}

TEST_F(KeyInputEventTest, CanCleanupKeyInputDevice) {
  constexpr int kFd = 3;  //Dateideskriptor"3"
  InitHelper(kFilePath, kFd, 0);

  // libevdev_free()Stellen Sie einfach sicher, dass das aufgerufen wird
  EXPECT_CALL(*mock_libevdev, libevdev_free(_)).Times(1);
  //Dateideskriptor"3"Wird voraussichtlich geschlossen
  EXPECT_CALL(*mock_io, IO_CLOSE(kFd)).WillOnce(Return(0));

  EXPECT_TRUE(CleanupKeyInputDevice());
}

Der Test besteht erfolgreich!

Dann ist dies der nächste. Das Aufrufen von Cleanup vor Init sollte fehlschlagen.

TEST_F(KeyInputEventTest, CleanupKeyInputDeviceFileNotOpenYet) {
  EXPECT_FALSE(CleanupKeyInputDevice());
}

Nun wird die Entwicklungsstruktur wie folgt initialisiert. Der Mock von IO_CLOSE () besteht wahrscheinlich den Test, wenn er -1 zurückgibt, wenn das Argument INVALID_FD lautet.

enum {INVALID_FD = -1};
static KeyInputDeviceStruct dev = {INVALID_FD, NULL};

bool CleanupKeyInputDevice() {
  libevdev_free(dev.evdev);
  int rc = IO_CLOSE(dev.fd);  //In nicht initialisiert, dev.fd ist UNGÜLTIG_FD(-1)
  if (rc < 0) return false;

  return true;
}

Mit anderen Worten, es ist ein Test.

TEST_F(KeyInputEventTest, CleanupKeyInputDevice) {
  EXPECT_CALL(*mock_io, IO_CLOSE(-1)).WillOnce(Return(-1));

  EXPECT_FALSE(CleanupKeyInputDevice());
}

Nun, Pass bauen und testen ... nein!

[ RUN      ] KeyInputEventTest.CleanupKeyInputDevice
Unexpected mock function call - returning default value.
    Function call: IO_CLOSE(3)
          Returns: 0
Google Mock tried the following 1 expectation, but it didn't match:

led_controller/test/key_input_event_test.cpp:111: EXPECT_CALL(*mock_io, IO_CLOSE(-1))...
  Expected arg #0: is equal to -1
           Actual: 3
         Expected: to be called any number of times
           Actual: never called - satisfied and active
[  FAILED  ] KeyInputEventTest.CleanupKeyInputDevice (0 ms)

Das Argument von IO_CLOSE () ist "3". Dieses Ergebnis ist natürlich. Das liegt daran, dass ein Test ausgeführt wird, der dev.fd "3" zuweist, bevor dieser Test ausgeführt wird! Da dev eine statische Struktur ist, ist ihre Lebensdauer so lang, wie das Programm ausgeführt wird. Mit anderen Worten, das Ergebnis dieses Tests hängt von anderen Testausführungen ab.

Einzelinstanzmodule (oder Klassen, die das Einzeltonnenmuster anwenden) sind in der Regel schwer zu testen. Dies liegt daran, dass ein unabhängiger Test nur geschrieben werden kann, wenn alle im vorherigen Test geänderten Zustände wiederhergestellt wurden. Mit Ausnahme von Modulen, die Einzelinstanzen sein müssen, ist es meiner Meinung nach besser, so viele Instanzen wie möglich anzunehmen.

Lassen Sie uns nun den Code so ändern, dass er mehrfach instanziiert werden kann. Dieser Fix erzwingt Änderungen an vorhandenen APIs. Sie können jedoch fortfahren, während Sie bestätigen, dass die bisher erstellten Tests auch mit der neuen API erfolgreich sind.

Fügen Sie die API wie folgt hinzu / ändern Sie sie, um sie zu mehreren Instanzen zu machen.

struct KeyInputDeviceStruct;
typedef struct KeyInputDeviceStruct *KeyInputDevice;

KeyInputDevice CreateKeyInputDevice();
bool InitKeyInputDevice(KeyInputDevice dev, const char *device_file);
bool CleanupKeyInputDevice(KeyInputDevice dev);
void DestroyKeyInputDevice(KeyInputDevice dev);

KeyInputDeviceStruct verfügt wie folgt über Zeiger auf Dateideskriptoren und libevdev-Strukturen:

typedef struct KeyInputDeviceStruct {
  int fd;
  struct libevdev *evdev;
} KeyInputDeviceStruct;

Create () reserviert Speicher, setzt Anfangswerte und gibt wie folgt einen Zeiger darauf zurück.

KeyInputDevice CreateKeyInputDevice() {
  KeyInputDevice dev = calloc(1, sizeof(KeyInputDeviceStruct));
  dev->fd = -1;
  dev->evdev = NULL;

  return dev;
}

Destroy () gibt den übergebenen Zeiger frei.

void DestroyKeyInputDevice(KeyInputDevice dev) {
  if(!dev) {
    free(dev);
    dev = NULL;
  }
}

Init () und Cleanup () bedienen nur den durch das Argument angegebenen Zeiger anstelle der zuvor als statische Variable definierten Struktur.

bool InitKeyInputDevice(KeyInputDevice dev, const char *device_file) {
  //  dev.fd = IO_OPEN(device_file, O_RDONLY|O_NONBLOCK);
  dev->fd = IO_OPEN(device_file, O_RDONLY|O_NONBLOCK);
...

Wenn Sie die API auf diese Weise ändern, ist der folgende zuvor fehlgeschlagene Cleanup () - Test erfolgreich.

TEST_F(KeyInputEventTest, CleanupKeyInputDevice) {
  EXPECT_CALL(*mock_io, IO_CLOSE(-1)).WillRepeatedly(Return(-1));

  EXPECT_FALSE(CleanupKeyInputDevice(dev_));
}

Übrigens werden in allen Tests Create () und Destroy () verwendet, um KeyInputDevice zu erstellen und zu zerstören. Um Doppelungen des Testcodes zu vermeiden, schreiben Sie die allgemeine Verarbeitung in SetUp () / TearDown () des Testgeräts. Behalten Sie Ihren Testcode DRY (Wiederholen Sie sich nicht).

    virtual void SetUp()
    {
      dev_ = CreateKeyInputDevice();
    }

    virtual void TearDown()
    {
      DestroyKeyInputDevice(dev_);
    }

Jetzt müssen alle APIs auf Nullzeiger vorbereitet werden. Wenn Sie beispielsweise einen Test wie diesen schreiben, stirbt der Test mit einem Segmentierungsfehler.

TEST_F(KeyInputEventTest, AllApiHaveNullPointerGuard) {
  const KeyInputDevice kNullPointer = NULL;
  EXPECT_FALSE(InitKeyInputDevice(kNullPointer, kFilePath));
  EXPECT_FALSE(CleanupKeyInputDevice(kNullPointer));
}

Lassen Sie uns am Eingang der Funktion einen Schutz gegen den Nullzeiger setzen.

bool InitKeyInputDevice(KeyInputDevice dev, const char *device_file) {
  if(dev == NULL) return false;
  // if(!dev)Nicht zu tun ist ein Hobby

Interne Struktur einkapseln

Das Modul, das wir erstellen, verfügt jetzt über einen Dateideskriptor für Ereignisgeräte und libevdev als Daten. ** Diese interne Struktur müssen Benutzer dieses Moduls nicht kennen. ** ** ** Der Benutzer muss nur wissen, wie eine Instanz von KeyInputDevice mit Create () erstellt und die erstellte Instanz an jede Funktion übergeben wird. Wenn Sie die interne Struktur dem Benutzer schlecht zugänglich machen, können Sie sich nicht beschweren, selbst wenn der Benutzer sie abhängig von der internen Struktur implementiert. Infolgedessen ** erstreckt sich der Effekt der Änderung der internen Struktur auf den Code des Benutzers, und im schlimmsten Fall kann die interne Struktur möglicherweise nicht geändert werden. ** ** **

Dieses Mal habe ich den Header in key_input_event.h und key_input_event_private.h aufgeteilt. Im ersteren werden nur die Informationen ** geschrieben, die der Benutzer zur Verwendung dieses Moduls benötigt **.

【key_input_event.h】

//Definieren Sie die Vorwärtsdeklaration der Struktur und ihren Zeigertyp als KeyInputDevice
struct KeyInputDeviceStruct;
typedef struct KeyInputDeviceStruct *KeyInputDevice;

KeyInputDevice CreateKeyInputDevice();
bool InitKeyInputDevice(KeyInputDevice dev, const char *device_file);
bool CleanupKeyInputDevice(KeyInputDevice dev);
void DestroyKeyInputDevice(KeyInputDevice dev);

Implementierungsdetails werden in privaten Headern definiert. 【key_input_event_private.h】

typedef struct KeyInputDeviceStruct {
  int fd;
  struct libevdev *evdev;
} KeyInputDeviceStruct;

Auf diese Weise kann die interne Struktur geändert werden, ohne sich auf den Benutzer auszudehnen. (Außer wenn sich der Benutzer in einem rauen Zustand befindet!)

[Zusatz] Zu diesem Zeitpunkt sieht noch niemand das KeyInputDeviceStruct. Daher wurde es geändert, um die Strukturdefinition in key_input_event.c zu schreiben.

Organisieren Sie die Initialisierungs- / Beendigungsverarbeitung von libevdev

Testcode

5 neue Tests hinzugefügt. Der Code wird weggelassen, da die Syntaxhervorhebung nicht so gut funktioniert und der Code schwer zu erkennen ist. github ist etwas besser. Wenn Sie also den gesamten Testcode sehen möchten, gehen Sie bitte zu ↓. github:key_input_event_test.cpp

Produktcode

Durch den Gedanken an testbaren Code entwickelte sich dieser natürlich zu einem Modul mit mehreren Instanzen. Die API lautet wie folgt.

struct KeyInputDeviceStruct;
typedef struct KeyInputDeviceStruct *KeyInputDevice;

KeyInputDevice CreateKeyInputDevice();
bool InitKeyInputDevice(KeyInputDevice dev, const char *device_file);
bool CleanupKeyInputDevice(KeyInputDevice dev);
void DestroyKeyInputDevice(KeyInputDevice dev);

Die Implementierung ist wie folgt.

KeyInputDevice CreateKeyInputDevice() {
  KeyInputDevice dev = calloc(1, sizeof(KeyInputDeviceStruct));
  dev->fd = -1;
  dev->evdev = NULL;

  return dev;
}

bool InitKeyInputDevice(KeyInputDevice dev, const char *device_file) {
  if(dev == NULL) return false;

  dev->fd = IO_OPEN(device_file, O_RDONLY|O_NONBLOCK);
  if (dev->fd < 0) {
    if (errno == EACCES)
      DEBUG_LOG("Fail to open file. You may need root permission.");
    return false;
  }

  int rc = libevdev_new_from_fd(dev->fd, &dev->evdev);
  if (rc < 0) return false;

  return true;
}

bool CleanupKeyInputDevice(KeyInputDevice dev) {
  if(dev == NULL) return false;

  libevdev_free(dev->evdev);
  int rc = IO_CLOSE(dev->fd);
  if (rc < 0) return false;

  return true;
}

void DestroyKeyInputDevice(KeyInputDevice dev) {
  if(dev == NULL) return;

  free(dev);
  dev = NULL;
}

Zu diesem Zeitpunkt kann nichts getan werden, aber die Produktcodeseite kann auch erstellt und ausgeführt werden. Die main.c des Produktcodes lautet wie folgt.

int main(void) {
  KeyInputDevice dev = CreateKeyInputDevice();
  InitKeyInputDevice(dev, "/dev/input/event2");
  CleanupKeyInputDevice(dev);
  DestroyKeyInputDevice(dev);

  return 0;
}

Aufgabenliste

Der Status der Aufgabenliste bezüglich der Tasteneingabe lautet wie folgt. Die am Anfang aufgeführten Punkte sind beendet.

Vorschau beim nächsten Mal

Erkennt das Drücken der Taste "A" und schließt die Implementierung von libevdev-bezogenen Modulen ab.

Nachtrag

Ich halte es für schwierig, einen Sinn dafür zu finden, dass die Rückgabewerte von Init () und Cleanup () bool sind. Die folgende Aufzählung wurde hinzugefügt und die Implementierung wurde geändert, um Code zurückzugeben. Indem Sie den Test und dann den Produktcode ändern, können Sie den Code sicher und mutig ändern.

enum {
  INPUT_DEV_SUCCESS = 0,
  INPUT_DEV_INIT_ERROR = -1,
  INPUT_DEV_CLEANUP_ERROR = -2,
};

Recommended Posts

Lassen Sie uns etwas entwickeln, das mit TDD ~ libevdev Initialisierungs- / Beendigungsverarbeitung ~ nahezu eingebettet ist
Lassen Sie uns mit TDD ~ Preparation ~ etwas entwickeln, das nahezu eingebettet ist
Lassen Sie uns mit TDD ~ Intermediate Review ~ etwas entwickeln, das dem Integrierten nahe kommt
Versuchen Sie, etwas zu entwickeln, das der Einbettung mit TDD nahe kommt ~ Problemauslösung ~
Lassen Sie uns mit TDD ~ Design pattern ~ etwas entwickeln, das dem Integrierten nahe kommt
Lassen Sie uns etwas entwickeln, das mit TDD ~ file open edition ~ nahezu eingebettet ist
Lassen Sie uns mit TDD ~ Key Input Detection Version ~ etwas entwickeln, das dem Integrierten nahe kommt
[Lass uns mit Python spielen] Bildverarbeitung zu Monochrom und Punkten