text: #define DISABLE_PICOJSON // Make sure JWT compiles with this flag
  
  #include <gtest/gtest.h>
  #include "jwt-cpp/jwt.h"
  #include "nlohmann/json.hpp"
  
  struct nlohmann_traits {
  	using json = nlohmann::json;
  	using value_type = json;
  	using object_type = json::object_t;
  	using array_type = json::array_t;
  	using string_type = std::string;
  	using number_type = double;
  	using integer_type = int64_t;
  	using boolean_type = bool;
  
  	static jwt::json::type get_type(const json &val) {
  		using jwt::json::type;
  
  		if (val.type() == json::value_t::boolean)
  			return type::boolean;
  		else if (val.type() == json::value_t::number_integer)
  			return type::integer;
  		else if (val.type() == json::value_t::number_float)
  			return type::number;
  		else if (val.type() == json::value_t::string)
  			return type::string;
  		else if (val.type() == json::value_t::array)
  			return type::array;
  		else if (val.type() == json::value_t::object)
  			return type::object;
  		else
  			throw std::logic_error("invalid type");
  	}
  
  	static json::object_t as_object(const json &val) {
  		if (val.type() != json::value_t::object)
  			throw std::bad_cast();
  		return val.get<json::object_t>();
  	}
  
  	static std::string as_string(const json &val) {
  		if (val.type() != json::value_t::string)
  			throw std::bad_cast();
  		return val.get<std::string>();
  	}
  
  	static json::array_t as_array(const json &val) {
  		if (val.type() != json::value_t::array)
  			throw std::bad_cast();
  		return val.get<json::array_t>();
  	}
  
  	static int64_t as_int(const json &val) {
  		if (val.type() != json::value_t::number_integer)
  			throw std::bad_cast();
  		return val.get<int64_t>();
  	}
  
  	static bool as_bool(const json &val) {
  		if (val.type() != json::value_t::boolean)
  			throw std::bad_cast();
  		return val.get<bool>();
  	}
  
  	static double as_number(const json &val) {
  		if (val.type() != json::value_t::number_float)
  			throw std::bad_cast();
  		return val.get<double>();
  	}
  
  	static bool parse(json &val, std::string str) {
  		val = json::parse(str.begin(), str.end());
  		return true;
  	}
  
  	static std::string serialize(const json &val) {
  		return val.dump();
  	}
  };
  
  TEST(NlohmannTest, BasicClaims) {
  	using nlohmann_claim = jwt::basic_claim<nlohmann_traits>;
  
  	const auto string = nlohmann_claim(std::string("string"));
  	const auto array = nlohmann_claim(std::set<std::string>{"string", "string"});
  	const auto integer = nlohmann_claim(159816816);
  }
  
  TEST(NlohmannTest, AudienceAsString) {
  
  	std::string token =
  			"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ0ZXN0In0."
  			"WZnM3SIiSRHsbO3O7Z2bmIzTJ4EC32HRBKfLznHhrh4";
  	auto decoded = jwt::decode<nlohmann_traits>(token);
  
  	ASSERT_TRUE(decoded.has_algorithm());
  	ASSERT_TRUE(decoded.has_type());
  	ASSERT_FALSE(decoded.has_content_type());
  	ASSERT_FALSE(decoded.has_key_id());
  	ASSERT_FALSE(decoded.has_issuer());
  	ASSERT_FALSE(decoded.has_subject());
  	ASSERT_TRUE(decoded.has_audience());
  	ASSERT_FALSE(decoded.has_expires_at());
  	ASSERT_FALSE(decoded.has_not_before());
  	ASSERT_FALSE(decoded.has_issued_at());
  	ASSERT_FALSE(decoded.has_id());
  
  	ASSERT_EQ("HS256", decoded.get_algorithm());
  	ASSERT_EQ("JWT", decoded.get_type());
  	auto aud = decoded.get_audience();
  	ASSERT_EQ(1, aud.size());
  	ASSERT_EQ("test", *aud.begin());
  }
  
  TEST(NlohmannTest, SetArray) {
  	std::vector<int64_t> vect = {
  		100,
  		20,
  		10
  	};
  	auto token = jwt::create<nlohmann_traits>()
  		.set_payload_claim("test", jwt::basic_claim<nlohmann_traits>(vect.begin(), vect.end()))
  		.sign(jwt::algorithm::none{});
  	ASSERT_EQ(token, "eyJhbGciOiJub25lIn0.eyJ0ZXN0IjpbMTAwLDIwLDEwXX0.");
  }
  
  TEST(NlohmannTest, SetObject) {
  	std::istringstream iss{"{\"api-x\": [1]}"};
  	jwt::basic_claim<nlohmann_traits> object;
  	iss >> object;
  	ASSERT_EQ(object.get_type() , jwt::json::type::object);
  
  	auto token = jwt::create<nlohmann_traits>()
  		.set_payload_claim("namespace", object)
  		.sign(jwt::algorithm::hs256("test"));
  	ASSERT_EQ(token, "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lc3BhY2UiOnsiYXBpLXgiOlsxXX19.F8I6I2RcSF98bKa0IpIz09fRZtHr1CWnWKx2za-tFQA");
  }
  
  TEST(NlohmannTest, VerifyTokenHS256) {
  	std::string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
  
  	auto verify = jwt::verify<jwt::default_clock, nlohmann_traits>({})
  		.allow_algorithm(jwt::algorithm::hs256{ "secret" })
  		.with_issuer("auth0");
  
  	auto decoded_token = jwt::decode<nlohmann_traits>(token);
  	verify.verify(decoded_token);
  }
  