[GH-ISSUE #107] Feature Request: Supporting unittests on MSVC #90

Closed
opened 2026-05-05 11:38:32 -06:00 by gitea-mirror · 6 comments
Owner

Originally created by @Alexhuszagh on GitHub (Jun 21, 2017).
Original GitHub issue: https://github.com/jmcnamara/libxlsxwriter/issues/107

Originally assigned to: @jmcnamara on GitHub.

Hi jmcnamara,

I've written a patch that would allow fully functional unittests on MSVC, with a few small patches.

  1. Changed __attribute__ to #defines, which are removed on MSVC (so the same functionality is kept elsewhere) in ctest.h.
  2. Grabbed a public domain gettimeofday implementation for Windows, for ctest.h.
  3. Conditionally compile iowin32.c if using MSVC, but not with MinGW or MSYS2.

Combined, these relatively small changes make the entire unittest suite work on Windows, without changing any other build systems. If this is of interest, I will submit a PR so you can review the changes. I have tested the changes on MSYS2, MSVC 2015, MSVC 2017, macOS with GCC and Clang, Linux with GCC and Clang, and all build normally.

Originally created by @Alexhuszagh on GitHub (Jun 21, 2017). Original GitHub issue: https://github.com/jmcnamara/libxlsxwriter/issues/107 Originally assigned to: @jmcnamara on GitHub. Hi jmcnamara, I've written a patch that would allow fully functional unittests on MSVC, with a few small patches. 1. Changed `__attribute__` to `#define`s, which are removed on MSVC (so the same functionality is kept elsewhere) in `ctest.h`. 2. Grabbed a [public domain](https://github.com/Alexpux/mingw-w64/blob/master/mingw-w64-crt/misc/gettimeofday.c) `gettimeofday` implementation for Windows, for `ctest.h`. 3. Conditionally compile `iowin32.c` if using MSVC, but not with MinGW or MSYS2. Combined, these relatively small changes make the entire unittest suite work on Windows, without changing any other build systems. If this is of interest, I will submit a PR so you can review the changes. I have tested the changes on MSYS2, MSVC 2015, MSVC 2017, macOS with GCC and Clang, Linux with GCC and Clang, and all build normally.
gitea-mirror 2026-05-05 11:38:32 -06:00
Author
Owner

@jmcnamara commented on GitHub (Jun 22, 2017):

Hi Alex,

Thanks for the suggestion.

At the moment getting the unittests to work with MSVC isn't a high priority.

A guide to building a sample app, or all the sample apps, with CMake and MSVC would be much more useful. Pinging @jimzshi on this as well.

John

<!-- gh-comment-id:310330600 --> @jmcnamara commented on GitHub (Jun 22, 2017): Hi Alex, Thanks for the suggestion. At the moment getting the unittests to work with MSVC isn't a high priority. A guide to building a sample app, or all the sample apps, with CMake and MSVC would be much more useful. Pinging @jimzshi on this as well. John
Author
Owner

@jmcnamara commented on GitHub (Jun 22, 2017):

P.S. It looks like the latest version of Ctest may be more Windows compatible: https://github.com/bvdberg/ctest

<!-- gh-comment-id:310332123 --> @jmcnamara commented on GitHub (Jun 22, 2017): P.S. It looks like the latest version of Ctest may be more Windows compatible: https://github.com/bvdberg/ctest
Author
Owner

@Alexhuszagh commented on GitHub (Jun 22, 2017):

@jmcnamara I quickly looked over it: it's most of the way there but it's missing a gettimeofday implementation, which was suggested in a PR.

For the other issue, I can create a sample app using cmake later today.

As far as the total diff to get CTest working, here it is (there are the other changes in IOAPI, but those are a single line). If you would like, I can make a PR there and then you can integrate the changes here.

diff --git a/a.h b/b.h
index 3aacf66..126e31b 100644
--- a/a.h
+++ b/b.h
@@ -43,6 +43,8 @@ struct ctest {
 #define __CTEST_MAGIC (0xdeadbeef)
 #ifdef __APPLE__
 #define __Test_Section __attribute__ ((unused,section ("__DATA, .ctest")))
+#elif defined(_MSC_VER)
+#define __Test_Section
 #else
 #define __Test_Section __attribute__ ((unused,section (".ctest")))
 #endif
@@ -60,11 +62,17 @@ struct ctest {
 
 #define CTEST_DATA(sname) struct sname##_data
 
+#ifndef _MSC_VER
+#define ATTR_WEAK __attribute__ ((weak))
+#else
+#define ATTR_WEAK
+#endif
+
 #define CTEST_SETUP(sname) \
-    void __attribute__ ((weak)) sname##_setup(struct sname##_data* data)
+    void ATTR_WEAK sname##_setup(struct sname##_data* data)
 
 #define CTEST_TEARDOWN(sname) \
-    void __attribute__ ((weak)) sname##_teardown(struct sname##_data* data)
+    void ATTR_WEAK sname##_teardown(struct sname##_data* data)
 
 #define __CTEST_INTERNAL(sname, tname, _skip) \
     void __FNAME(sname, tname)(); \
@@ -137,11 +145,17 @@ void assert_fail(const char* caller, int line);
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
-#include <sys/time.h>
-#include <unistd.h>
 #include <stdint.h>
 #include <stdlib.h>
 
+#ifndef _MSC_VER
+#include <sys/time.h>
+#include <unistd.h>
+#else
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
 #ifdef __APPLE__
 #include <dlfcn.h>
 #endif
@@ -314,6 +328,44 @@ static int suite_filter(struct ctest* t) {
     return strncmp(suite_name, t->ssname, strlen(suite_name)) == 0;
 }
 
+
+#ifdef _MSC_VER
+// We need a portable `gettimeofday` implementation.
+// winsock2.h includes `struct timeval`.
+
+#define EPOCH_TIME 116444736000000000ull
+#define HECTONANOSEC_PER_SEC 10000000ull
+
+#ifndef _TIMEVAL_DEFINED
+#define _TIMEVAL_DEFINED
+struct timeval {
+    long tv_sec;
+    long tv_usec;
+};
+#endif
+
+static int gettimeofday(struct timeval* tp, void* tz)
+{
+    int res = 0;
+    union {
+        uint64_t ns100;
+        FILETIME file_time;
+    } now;
+    SYSTEMTIME system_time;
+    uint64_t value;
+
+    if (tp != NULL) {
+        GetSystemTimeAsFileTime(&now.file_time);
+        now.ns100 -= EPOCH_TIME;
+        tp->tv_sec = now.ns100 / HECTONANOSEC_PER_SEC;
+        tp->tv_usec = (long) (now.ns100 % HECTONANOSEC_PER_SEC) / 10;
+    }
+
+    return res;
+}
+#endif
+
+
 static uint64_t getCurrentTime() {
     struct timeval now;
     gettimeofday(&now, NULL);
<!-- gh-comment-id:310448540 --> @Alexhuszagh commented on GitHub (Jun 22, 2017): @jmcnamara I quickly looked over it: it's most of the way there but it's missing a `gettimeofday` implementation, which was suggested in a PR. For the other issue, I can create a sample app using cmake later today. As far as the total diff to get CTest working, here it is (there are the other changes in IOAPI, but those are a single line). If you would like, I can make a PR there and then you can integrate the changes here. ```diff diff --git a/a.h b/b.h index 3aacf66..126e31b 100644 --- a/a.h +++ b/b.h @@ -43,6 +43,8 @@ struct ctest { #define __CTEST_MAGIC (0xdeadbeef) #ifdef __APPLE__ #define __Test_Section __attribute__ ((unused,section ("__DATA, .ctest"))) +#elif defined(_MSC_VER) +#define __Test_Section #else #define __Test_Section __attribute__ ((unused,section (".ctest"))) #endif @@ -60,11 +62,17 @@ struct ctest { #define CTEST_DATA(sname) struct sname##_data +#ifndef _MSC_VER +#define ATTR_WEAK __attribute__ ((weak)) +#else +#define ATTR_WEAK +#endif + #define CTEST_SETUP(sname) \ - void __attribute__ ((weak)) sname##_setup(struct sname##_data* data) + void ATTR_WEAK sname##_setup(struct sname##_data* data) #define CTEST_TEARDOWN(sname) \ - void __attribute__ ((weak)) sname##_teardown(struct sname##_data* data) + void ATTR_WEAK sname##_teardown(struct sname##_data* data) #define __CTEST_INTERNAL(sname, tname, _skip) \ void __FNAME(sname, tname)(); \ @@ -137,11 +145,17 @@ void assert_fail(const char* caller, int line); #include <stdarg.h> #include <stdio.h> #include <string.h> -#include <sys/time.h> -#include <unistd.h> #include <stdint.h> #include <stdlib.h> +#ifndef _MSC_VER +#include <sys/time.h> +#include <unistd.h> +#else +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + #ifdef __APPLE__ #include <dlfcn.h> #endif @@ -314,6 +328,44 @@ static int suite_filter(struct ctest* t) { return strncmp(suite_name, t->ssname, strlen(suite_name)) == 0; } + +#ifdef _MSC_VER +// We need a portable `gettimeofday` implementation. +// winsock2.h includes `struct timeval`. + +#define EPOCH_TIME 116444736000000000ull +#define HECTONANOSEC_PER_SEC 10000000ull + +#ifndef _TIMEVAL_DEFINED +#define _TIMEVAL_DEFINED +struct timeval { + long tv_sec; + long tv_usec; +}; +#endif + +static int gettimeofday(struct timeval* tp, void* tz) +{ + int res = 0; + union { + uint64_t ns100; + FILETIME file_time; + } now; + SYSTEMTIME system_time; + uint64_t value; + + if (tp != NULL) { + GetSystemTimeAsFileTime(&now.file_time); + now.ns100 -= EPOCH_TIME; + tp->tv_sec = now.ns100 / HECTONANOSEC_PER_SEC; + tp->tv_usec = (long) (now.ns100 % HECTONANOSEC_PER_SEC) / 10; + } + + return res; +} +#endif + + static uint64_t getCurrentTime() { struct timeval now; gettimeofday(&now, NULL); ```
Author
Owner

@jmcnamara commented on GitHub (Jun 23, 2017):

If you would like, I can make a PR there and then you can integrate the changes here.

That would be the best option. If you can't get it upstream into CTest you can submit a PR here and I'll add it into the libxlsxwriter copy.

<!-- gh-comment-id:310610818 --> @jmcnamara commented on GitHub (Jun 23, 2017): > If you would like, I can make a PR there and then you can integrate the changes here. That would be the best option. If you can't get it upstream into CTest you can submit a PR here and I'll add it into the libxlsxwriter copy.
Author
Owner

@jmcnamara commented on GitHub (Jun 27, 2017):

Hi @Alexhuszagh, just submit a PR for the changes above and I'll merge it. No need to try upstream it to CTest first.

<!-- gh-comment-id:311218299 --> @jmcnamara commented on GitHub (Jun 27, 2017): Hi @Alexhuszagh, just submit a PR for the changes above and I'll merge it. No need to try upstream it to CTest first.
Author
Owner

@Alexhuszagh commented on GitHub (Jul 10, 2017):

Hi @jmcnamara, sorry for the delay, I've been busy on another project. I'll make a PR for this, and have separate commits for each of the changes.

<!-- gh-comment-id:314239032 --> @Alexhuszagh commented on GitHub (Jul 10, 2017): Hi @jmcnamara, sorry for the delay, I've been busy on another project. I'll make a PR for this, and have separate commits for each of the changes.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: github-starred/libxlsxwriter#90
No description provided.