Can't get test to run on Visual Studio 2019 using Microsoft CppUnitTest Framework - c++

I've a function std::vector<Token> tokenize(const std::string& s) that I want to unit test. The Token struct is defined as follows:
enum class Token_type { plus, minus, mult, div, number };
struct Token {
Token_type type;
double value;
}
I have set up CppUnitTest and can get toy tests such as 1 + 1 == 2 to run. But when I try to run a test on my tokenize function it gives me this error:
Error C2338: Test writer must define specialization of ToString<const Q& q> for your class class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> > __cdecl Microsoft::VisualStudio::CppUnitTestFramework::ToString<class std::vector<struct Token,class std::allocator<struct Token> >>(const class std::vector<struct Token,class std::allocator<struct Token> > &).
My testing code is this:
#include <vector>
#include "pch.h"
#include "CppUnitTest.h"
#include "../calc-cli/token.hpp"
using namespace std;
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace test_tokens {
TEST_CLASS(test_tokenize) {
public:
TEST_METHOD(binary_operation_plus) {
auto r = tokenize("1+2");
vector<Token> s = {
Token{ Token_type::number, 1.0 },
Token{ Token_type::plus },
Token{ Token_type::number, 2.0}
};
Assert::AreEqual(r, s);
}
};
}
What's causing the error and how can I fix this?

When you use Assert::AreEqual the framework wants to be able to display a string that describes the objects if the assert fails. It uses the templated function ToString for this, which includes specializations for all the basic data types. For any other data type, you would have to provide a specialization that knows how to format the data into a meaningful string.
The simplest solution is to use a different type of assert that doesn't require ToString. For example:
Assert::IsTrue(r == s, L"Some descriptive failure message");
The other option is to create the ToString specialization that the assert needs:
#include <CppUnitTestAssert.h>
namespace Microsoft {
namespace VisualStudio {
namespace CppUnitTestFramework {
template<> static inline std::wstring ToString(const std::vector<Token> &t)
{
// Write some code here to create a descriptive std::wstring
return std::wstring("My object description");
}
}
}
}
I would only go to the trouble of making a specialization if I'm going to be writing a lot of tests using that same object type, and I want to automatically describe the objects.

Related

C++: Derive a class template from QuantLib::PiecewiseYieldCurve

I would like to derive a class template from QuantLib::PiecewiseYieldCurve. This is my derived class definition:
#include <ql\termstructures\yield\piecewiseyieldcurve.hpp>
#include <MarKetQuote\include\OISQuote.h>
#include <vector>
using namespace QuantLib;
/*! \brief Class to bootstrap an OIS curve.
*/
template <class Traits, class Interpolator,
template <class> class Bootstrap = IterativeBootstrap>
class OISCurve : public PiecewiseYieldCurve < Traits, Interpolator, Bootstrap >
{
private:
/** Typedef to refer to the specialized class.
It was necessary to add it in other to be able to declare the constructor as in QuantLib::PiecewiseYieldCurve.
*/
typedef OISCurve<Traits, Interpolator, Bootstrap> this_ois_curve;
public:
/** Constructor.
*/
OISCurve(
const Date& referenceDate,
const std::vector<OISQuote>& quotes,
const DayCounter& dayCounter,
Real accuracy,
const Interpolator& i = Interpolator(),
const Bootstrap<this_ois_curve>& bootstrap = Bootstrap<this_ois_curve>());
};
OISQuote is simply a class derived from QuantLib::SimpleQuote. I'm not familiar with this type of complicated templating, but to my limited understanding the above should be ok. It compiles actually. The problem arises when I try to instantiate a specialized class like this:
OISCurve<Discount, LogLinear> oisCurve = OISCurve<Discount, LogLinear>(Date::todaysDate(), quotes, Actual360(), 1.0e-12);
I get a linking error LNK2019 (using visual studio):
main.obj : error LNK2019: unresolved external symbol "public: __cdecl OISCurve<struct QuantLib::Discount,class QuantLib::LogLinear,class QuantLib::IterativeBootstrap>::OISCurve<struct QuantLib::Discount,class QuantLib::LogLinear,class QuantLib::IterativeBootstrap>(class QuantLib::Date const &,class std::vector<class OISQuote,class std::allocator<class OISQuote> > const &,class QuantLib::DayCounter const &,double,class QuantLib::LogLinear const &)" (??0?$OISCurve#UDiscount#QuantLib##VLogLinear#2#VIterativeBootstrap#2###QEAA#AEBVDate#QuantLib##AEBV?$vector#VOISQuote##V?$allocator#VOISQuote###std###std##AEBVDayCounter#2#NAEBVLogLinear#2##Z) referenced in function main
1>C:\Users\u8998\PricingEngine\build\Debug\main.exe : fatal error LNK1120: 1 unresolved externals
Thanks for the help.
EDIT:
Sorry for the late reply. Thank you #LuigiBallabio and #StudentT for your answers. My problem ended up being caused by my inexperience with class templates. I had my declaration in a header file and my implementation in a cpp file exactly as with any other class. Following the guidelines in the accepted answer of this question I modified my code accordingly:
OISCurve.h
#ifndef OIS_CURVE_H
#define OIS_CURVE_H
#include <ql\termstructures\yield\piecewiseyieldcurve.hpp>
#include <ql\termstructures\yield\ratehelpers.hpp>
#include <ql\quote.hpp>
#include <vector>
#include <boost\shared_ptr.hpp>
using namespace QuantLib;
template <class Traits, class Interpolator,
template <class> class Bootstrap = IterativeBootstrap>
class OISCurve : public PiecewiseYieldCurve < Traits, Interpolator, Bootstrap >
{
public:
OISCurve(const Date& referenceDate,
const std::vector<boost::shared_ptr<Quote>>& quotes,
const DayCounter& dayCounter,
Real accuracy);
friend std::vector<boost::shared_ptr<RateHelper>> getRateHelpers(const std::vector<boost::shared_ptr<Quote>>& quotes);
private:
std::vector<boost::shared_ptr<Quote>> quotes_;
};
#include <CurveBootstrapping\src\OISCurve.cpp>
#endif
OISCurve.cpp
#include "OISCurve.h"
#include <ql\errors.hpp>
#include <algorithm>
#include <boost\foreach.hpp>
#include <ql\termstructures\yield\oisratehelper.hpp>
#include <MarKetQuote\include\OISQuote.h>
#include <ql\handle.hpp>
#include <ql\indexes\ibor\eonia.hpp>
#ifndef OIS_CURVE_IMPL
#define OIS_CURVE_IMPL
template <class T, class I, template <class> class B>
OISCurve<T, I, B>::OISCurve(
const Date& referenceDate,
const std::vector<boost::shared_ptr<Quote>>& quotes,
const DayCounter& dayCounter,
Real accuracy)
: PiecewiseYieldCurve < T, I, B >(referenceDate,
initializeQuotesAndGetRateHelpers(quotes),
dayCounter,
accuracy)
{
std::cout << "constructor works" << std::endl;
}
std::vector<boost::shared_ptr<RateHelper>> getRateHelpers(const std::vector<boost::shared_ptr<Quote>>& quotes)
{
QL_REQUIRE(std::all_of(quotes.begin(), quotes.end(), [](boost::shared_ptr<Quote> quote){ return boost::dynamic_pointer_cast<OISQuote>(quote) != 0; }),
"All quotes must be OISQuotes!");
std::vector<boost::shared_ptr<RateHelper>> rateHelpers;
BOOST_FOREACH(boost::shared_ptr<Quote> quote, quotes)
{
rateHelpers.push_back(boost::shared_ptr<RateHelper>(new OISRateHelper(2,
boost::dynamic_pointer_cast<OISQuote>(quote)->tenor(),
Handle<Quote>(quote),
boost::shared_ptr<OvernightIndex>(new Eonia()))));
}
return rateHelpers;
}
#endif
This is the solution i liked the most.
I don't think this questions relates to quantitative finance at all, but I'll answer anyway.
You have not provided an implementation to the constructor of the class OISCurve.
To link your program, do this:
OISCurve(
const Date& referenceDate,
const std::vector<OISQuote>& quotes,
const DayCounter& dayCounter,
Real accuracy,
const Interpolator& i = Interpolator(),
const Bootstrap<this_ois_curve>& bootstrap = Bootstrap<this_ois_curve>())
: <Call Parent Constructor>
{
}
You will need to replace with a call to an actual constructor defined in PiecewiseYieldCurve. There are six such constructors, so you will need to select the one that you think most appropriate. Please note that you will need to give the parent constructor a list of instruments, but it's missing in your constructor definition.

How to compare two iterators for unit test on VS2013?

code :
#include "stdafx.h"
#include "CppUnitTest.h"
#include <vector>
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace unit_test
{
TEST_CLASS(test_iterator)
{
public:
TEST_METHOD(vector_with_int)
{
std::vector<int> samples;
Assert::AreEqual(samples.begin(), samples.begin());
}
};
}
When compiling :
Error 1 error C2338: Test writer must define specialization of ToString for your class class std::basic_string,class std::allocator > __cdecl Microsoft::VisualStudio::CppUnitTestFramework::ToString > >>(const class std::_Vector_iterator > > &). c:\program files (x86)\microsoft visual studio 12.0\vc\unittest\include\cppunittestassert.h 66 1 unit_test
How to fix this problem? Should I use another framework instead?
You might want to subtract begin from each iterator (if they're random iterators) so you're comparing size_type offsets rather than iterator types:
Assert::AreEqual(samples.begin() - samples.begin(), samples.begin() - samples.begin());
Just add something like this before your tests:
namespace Microsoft { namespace VisualStudio { namespace CppUnitTestFramework {
using vecint_itr = typename std::vector<int>::iterator;
template<> inline std::wstring ToString<vecint_itr>(vecint_itr const & t)
{
return L"vecint_itr"; // replace with string with whatever you like
}
}}}
This injects a ToString function into the CppUnitTestFramework, which is needed to convert your iterator into a string value that can be displayed by the testing framework. This is exactly what the error message is asking you to do.

Comparing an error code enum with std::error_code

I'm using the C++11 system_error error code library to create a custom error class for a library I'm making. I've done this before with boost::error_code, but I can't quite it get it working with std::error_code. I'm using GCC 4.6.
Basically, I've laid out all the boilerplate code to create an error class, an error_category, and the conversion routines in the STD namespace to convert my custom enums into an std::error_code object:
namespace mylib
{
namespace errc {
enum my_error
{
failed = 0
};
inline const char* error_message(int c)
{
static const char* err_msg[] =
{
"Failed",
};
assert(c < sizeof(err_msg) / sizeof(err_msg[0]));
return err_msg[c];
}
class my_error_category : public std::error_category
{
public:
my_error_category()
{ }
std::string message(int c) const
{
return error_message(c);
}
const char* name() const { return "My Error Category"; }
const static error_category& get()
{
const static my_error_category category_const;
return category_const;
}
};
} // end namespace errc
} // end namespace mylib
namespace std {
inline error_code make_error_code(mylib::errc::my_error e)
{
return error_code(static_cast<int>(e), mylib::errc::my_error_category::get());
}
template<>
struct is_error_code_enum<mylib::errc::my_error>
: std::true_type
{ };
The problem is, implicit conversion between my error code enums and std::error_code objects doesn't seem to be working, so I can't for example try and compare an instance of std::error_code with enum literals:
int main()
{
std::error_code ec1 = std::make_error_code(mylib::errc::failed); // works
std::error_code ec2 = mylib::errc::failed; // doesn't compile
bool result = (ec2 == mylib::errc::failed); // doesn't compile
}
The expression ec2 == mylib::errc::failed won't compile - I have to say ec2 == std::make_error_code(mylib::errc::failed).
The error the compiler emits is:
In file included from test6.cc:3:0:
/usr/include/c++/4.6/system_error: In constructor ‘std::error_code::error_code(_ErrorCodeEnum, typename std::enable_if<std::is_error_code_enum<_ErrorCodeEnum>::value>::type*) [with _ErrorCodeEnum = mylib::errc::my_error, typename std::enable_if<std::is_error_code_enum<_ErrorCodeEnum>::value>::type = void]’:
test6.cc:70:37: instantiated from here
/usr/include/c++/4.6/system_error:127:9: error: cannot convert ‘mylib::errc::my_error’ to ‘std::errc’ for argument ‘1’ to ‘std::error_code std::make_error_code(std::errc)’
And here's an Ideone link.
So, why isn't this working? Do I need additional boilerplate code to enable mylib::errc::my_error enums to be implicitly convertible to std::error_code? I thought that the specialization of std::make_error_code takes care of that?
You have to move error_code make_error_code(mylib::errc::my_error e) function from std to your error namespace (mylib::errc). Please check http://ideone.com/eSfee.

Error C2888 migrating from VC9 to VC10

I am trying to compile solutions and projects on MSVC++ 10 that worked fine in MSVC++ 9, and I am having trouble with it, mostly getting the following message:
error C2888: 'std::hash' : symbol cannot be defined within namespace 'tr1'
on the following code:
namespace std {
namespace tr1 {
template <>
struct hash< Rubedo::eChannelFamily >
{
std::size_t operator()( const Rubedo::eChannelFamily& Key ) const
{
return ( int ) Key;
}
};
}}
I would be perfectly happy if I could do one of the following:
Modify the code to fix the bugs and compile cleanly;
Force the compiler to behave like MSVC++ 9.0.
How would I do something like that?
Thank you very much in advance.
hash is in namespace std in VS2010, as it's part of C++0x's Standard library, not std::tr1. Just remove the tr1 section and the compiler should be fine.
template<> class std::hash< Rubedo::eChannelFamily >>
: public std::unary_function<const Rubedo::eChannelFamily, size_t>
{
public:
size_t operator()(const Rubedo::eChannelFamily& ref) const {
return ( int ) ref;
}
};
This is a fairly trivial modification of a hash I have for my own type which compiles successfully.
You've to inherit unary_function like this and tr1 is not needed anymore,
namespace std
{
template <>
struct hash<Rubedo::eChannelFamily> : public unary_function<Rubedo::eChannelFamily, size_t>
{
size_t operator()(const Rubedo::eChannelFamily& key) const
{
return (size_t) key;
}
};
}

'Scanner' does not name a type error in g++

I'm trying to compile code in g++ and I get the following errors:
In file included from scanner.hpp:8,
from scanner.cpp:5:
parser.hpp:14: error: ‘Scanner’ does not name a type
parser.hpp:15: error: ‘Token’ does not name a type
Here's my g++ command:
g++ parser.cpp scanner.cpp -Wall
Here's parser.hpp:
#ifndef PARSER_HPP
#define PARSER_HPP
#include <string>
#include <map>
#include "scanner.hpp"
using std::string;
class Parser
{
// Member Variables
private:
Scanner lex; // Lexical analyzer
Token look; // tracks the current lookahead token
// Member Functions
<some function declarations>
};
#endif
and here's scanner.hpp:
#ifndef SCANNER_HPP
#define SCANNER_HPP
#include <iostream>
#include <cctype>
#include <string>
#include <map>
#include "parser.hpp"
using std::string;
using std::map;
enum
{
// reserved words
BOOL, ELSE, IF, TRUE, WHILE, DO, FALSE, INT, VOID,
// punctuation and operators
LPAREN, RPAREN, LBRACK, RBRACK, LBRACE, RBRACE, SEMI, COMMA, PLUS, MINUS, TIMES,
DIV, MOD, AND, OR, NOT, IS, ADDR, EQ, NE, LT, GT, LE, GE,
// symbolic constants
NUM, ID, ENDFILE, ERROR
};
class Token
{
public:
int tag;
int value;
string lexeme;
Token() {tag = 0;}
Token(int t) {tag = t;}
};
class Num : public Token
{
public:
Num(int v) {tag = NUM; value = v;}
};
class Word : public Token
{
public:
Word() {tag = 0; lexeme = "default";}
Word(int t, string l) {tag = t; lexeme = l;}
};
class Scanner
{
private:
int line; // which line the compiler is currently on
int depth; // how deep in the parse tree the compiler is
map<string,Word> words; // list of reserved words and used identifiers
// Member Functions
public:
Scanner();
Token scan();
string printTag(int);
friend class Parser;
};
#endif
anyone see the problem? I feel like I'm missing something incredibly obvious.
parser.hpp incluser scanner.hpp and vice versa.
So one file evalated before the other.
You can use a forward declaration like
class Scanner;
or reorginaze your headers
You are including Scanner.hpp in Parser.hpp and you are also including Parser.hpp in Scanner.hpp.
If you include Scanner.hpp in your source file then the definition of the Parser class will appear before the definition of the Scanner class and you will get the error you are seeing.
Resolve the circular dependency and your problem will go away (headers should never circularly depend on each other for types).
You have circular #include reference: one header file includes another and vice versa. You need to break this loop somehow.