Skip to content

Commit

Permalink
Improve unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
hunyadi committed Dec 4, 2024
1 parent 18c3d58 commit 19e0e0b
Show file tree
Hide file tree
Showing 7 changed files with 231 additions and 177 deletions.
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"cSpell.words": [
"árvíztűrő",
"Deallocator",
"jarray",
"javabind",
Expand All @@ -21,7 +22,8 @@
"jthrowable",
"Levente",
"Ljava",
"tparam"
"tparam",
"tükörfúrógép"
],
"C_Cpp.autoAddFileAssociations": false,
"C_Cpp.default.cppStandard": "c++17",
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ else()
endif()

# shared library for unit tests
add_library(javabind_native SHARED test/javabind.cpp)
add_library(javabind_native SHARED test/javabind.cpp test/format.hpp)
target_link_libraries(javabind_native PRIVATE javabind)

# code generator
Expand Down
8 changes: 4 additions & 4 deletions java/hu/info/hunyadi/test/StaticSample.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ public class StaticSample {

public static native long pass_long(long value);

public static native byte pass_cast_byte(byte value);
public static native byte pass_cast_byte(byte value, String expected);

public static native short pass_cast_short(short value);
public static native short pass_cast_short(short value, String expected);

public static native int pass_cast_int(int value);
public static native int pass_cast_int(int value, String expected);

public static native long pass_cast_long(long value);
public static native long pass_cast_long(long value, String expected);

public static native short pass_widen_byte(short value);

Expand Down
12 changes: 7 additions & 5 deletions java/hu/info/hunyadi/test/TestJavaBind.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,16 @@ public static void main(String[] args) {
assert StaticSample.pass_bool(false) == false;
assert StaticSample.pass_char('A') == 'A';
assert StaticSample.pass_short(Short.MIN_VALUE) == Short.MIN_VALUE;
assert StaticSample.pass_short(Short.MIN_VALUE) == Short.MIN_VALUE;
assert StaticSample.pass_short(Short.MAX_VALUE) == Short.MAX_VALUE;
assert StaticSample.pass_int(Integer.MIN_VALUE) == Integer.MIN_VALUE;
assert StaticSample.pass_int(Integer.MAX_VALUE) == Integer.MAX_VALUE;
assert StaticSample.pass_long(Long.MIN_VALUE) == Long.MIN_VALUE;
assert StaticSample.pass_long(Long.MAX_VALUE) == Long.MAX_VALUE;
assert StaticSample.pass_float(2.5f) == 2.5f;
assert StaticSample.pass_float(Float.MIN_VALUE) == Float.MIN_VALUE;
assert StaticSample.pass_float(Float.MAX_VALUE) == Float.MAX_VALUE;
assert StaticSample.pass_double(1.125) == 1.125;
assert StaticSample.pass_double(Double.MIN_VALUE) == Double.MIN_VALUE;
assert StaticSample.pass_double(Double.MAX_VALUE) == Double.MAX_VALUE;
assert StaticSample.pass_foo_bar(FooBar.Foo) == FooBar.Foo;
assert StaticSample.pass_foo_bar(FooBar.Bar) == FooBar.Bar;
Expand All @@ -55,10 +57,10 @@ public static void main(String[] args) {
StaticSample.pass_utf16_string("árvíztűrő tükörfúrógép");
System.out.println("PASS: class functions with simple types");

assert StaticSample.pass_cast_byte(Byte.MIN_VALUE) == Byte.MIN_VALUE;
assert StaticSample.pass_cast_short(Short.MIN_VALUE) == Short.MIN_VALUE;
assert StaticSample.pass_cast_int(Integer.MIN_VALUE) == Integer.MIN_VALUE;
assert StaticSample.pass_cast_long(Long.MIN_VALUE) == Long.MIN_VALUE;
assert StaticSample.pass_cast_byte(Byte.MIN_VALUE, "128") == Byte.MIN_VALUE;
assert StaticSample.pass_cast_short(Short.MIN_VALUE, "32768") == Short.MIN_VALUE;
assert StaticSample.pass_cast_int(Integer.MIN_VALUE, "2147483648") == Integer.MIN_VALUE;
assert StaticSample.pass_cast_long(Long.MIN_VALUE, "9223372036854775808") == Long.MIN_VALUE;
System.out.println("PASS: class functions with casting unsigned integer types");

short max_unsigned_byte = 255;
Expand Down
1 change: 1 addition & 0 deletions launch.bat
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@echo off
setlocal
chcp 65001

rem Build the C++ library
cmake -B build -D JAVABIND_INTEGER_SIGNED_CAST=ON -D JAVABIND_INTEGER_WIDENING_CONVERSION=OFF
Expand Down
178 changes: 178 additions & 0 deletions test/format.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/**
* javabind: effective C++ and Java interoperability
* @see https://github.com/hunyadi/javabind
*
* Copyright (c) 2024 Levente Hunyadi
*
* This work is licensed under the terms of the MIT license.
* For a copy, see <https://opensource.org/licenses/MIT>.
*/

#pragma once
#include <chrono>
#include <optional>
#include <vector>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <ctime>
#include <iostream>

inline bool time_to_struct(const time_t* timer, struct tm* buf)
{
#if defined(_MSC_VER)
return gmtime_s(buf, timer) == 0;
#else
return gmtime_r(timer, buf) != nullptr;
#endif
}

inline std::string to_string(const std::chrono::system_clock::time_point& instant)
{
auto duration_s = std::chrono::duration_cast<std::chrono::seconds>(instant.time_since_epoch());
auto duration_ns = std::chrono::duration_cast<std::chrono::nanoseconds>((instant - duration_s).time_since_epoch());

if (duration_ns.count() < 0) {
// ensure nanoseconds part is always non-negative
duration_s -= std::chrono::seconds(1);
duration_ns += std::chrono::nanoseconds(1'000'000'000);
}

// use 400-year periodicity of Gregorian calendar
unsigned int periods = 0;
while (duration_s.count() < 0) {
// ensure seconds part is always non-negative
duration_s += std::chrono::hours(24 * 146'097);
++periods;
}

unsigned long long ns = duration_ns.count();
std::time_t tv = static_cast<std::time_t>(duration_s.count());
std::tm tp;
if (!time_to_struct(&tv, &tp)) {
return std::string("[ERROR]");
}

// 1984-01-01 01:02:03.123456789Z
char buf[64];
int n = std::snprintf(buf, sizeof(buf), "%.4d-%02u-%02u %02u:%02u:%02u.%09lluZ",
tp.tm_year + 1900 - 400 * periods,
tp.tm_mon + 1,
tp.tm_mday,
tp.tm_hour,
tp.tm_min,
tp.tm_sec,
ns
);
return std::string(buf, buf + n);
}

inline std::ostream& operator<<(std::ostream& os, const std::chrono::nanoseconds& ns)
{
return os << ns.count() << "ns";
}

inline std::ostream& operator<<(std::ostream& os, const std::chrono::microseconds& us)
{
return os << us.count() << "us";
}

inline std::ostream& operator<<(std::ostream& os, const std::chrono::milliseconds& ms)
{
return os << ms.count() << "ms";
}

inline std::ostream& operator<<(std::ostream& os, const std::chrono::seconds& s)
{
return os << s.count() << "s";
}

inline std::ostream& operator<<(std::ostream& os, const std::chrono::minutes& m)
{
return os << m.count() << "m";
}

inline std::ostream& operator<<(std::ostream& os, const std::chrono::hours& h)
{
return os << h.count() << "h";
}

inline std::ostream& operator<<(std::ostream& os, const std::chrono::system_clock::time_point& instant)
{
return os << to_string(instant);
}

template <typename T>
std::ostream& operator<<(std::ostream& os, const std::optional<T>& opt)
{
if (opt.has_value()) {
return os << "{" << opt.value() << "}";
} else {
return os << "nullopt";
}
}

template <typename K, typename V>
std::ostream& operator<<(std::ostream& os, const std::pair<K, V>& pair)
{
return os << pair.first << ": " << pair.second;
}

template <typename L>
std::ostream& write_collection(std::ostream& os, const L& list, char left, char right)
{
os << left;
if (!list.empty()) {
auto&& it = list.begin();
os << *it;

for (++it; it != list.end(); ++it) {
os << ", " << *it;
}
}
os << right;
return os;
}

template <typename L>
std::ostream& write_list(std::ostream& os, const L& list)
{
return write_collection(os, list, '[', ']');
}

template <typename S>
std::ostream& write_set(std::ostream& os, const S& set)
{
return write_collection(os, set, '{', '}');
}

template <typename... Args>
std::ostream& operator<<(std::ostream& os, const std::vector<Args...>& list)
{
return write_list(os, list);
}

template <typename... Args>
std::ostream& operator<<(std::ostream& os, const std::set<Args...>& set)
{
return write_set(os, set);
}

template <typename... Args>
std::ostream& operator<<(std::ostream& os, const std::unordered_set<Args...>& set)
{
return write_set(os, set);
}

template <typename... Args>
std::ostream& operator<<(std::ostream& os, const std::map<Args...>& set)
{
return write_set(os, set);
}

template <typename... Args>
std::ostream& operator<<(std::ostream& os, const std::unordered_map<Args...>& set)
{
return write_set(os, set);
}
Loading

0 comments on commit 19e0e0b

Please sign in to comment.