// This is example code used in an article about X-Macros at
// http://op.closedformodification.com/2006/06/18/x-macros/
// This software is in the public domain. You can do what you want with it.
// This software is provided as is. No claim is made about any kind
// of usefulness in any area.

#include <string>
#include <iostream>

#define assertEquals(exp1, exp2) \
		_assertEquals(__LINE__, exp1, exp2);

namespace
{

// Implement a minimal testing framework
int gErrorCount = 0;
    
template<class T, class U>
void _assertEquals(int line, T exp1, U exp2)
{
    if (exp1!=exp2)
    {
        std::cout << "Error: Line " 
			      << line << "; " 
			      << exp1 << "!="  << exp2 
			      << std::endl;
        gErrorCount++;
    }
}

// (1) The code generation macro. Each X-Macro therein
// receives the type and the name of the new member

#define GENERATE_PROPS                          \
X(int, IntValue1, 100)                          \
X(std::string, StringValue1, "testValue1")      \
X(float, FloatValue1, 200.5f)                           \
X(int, IntValue2, 200)


// (2) This is the class that will hold all our members

class Properties
{    
public: 
// (3) The constructor: Set all members to their default
#define X(tp, name, tv) m_##name = tp();
    Properties()
    {
        GENERATE_PROPS
    }
#undef X

// (4) The getters, setters and members themselves 

#define X(tp, name, tv) \
public:                                                         \
    const tp& get##name() const {return m_##name;}              \
    void set##name(const tp& in##name) {m_##name  = in##name;}   \
private: tp m_##name;
    GENERATE_PROPS
#undef X
   
};

} // unnamed namespace

    
int main()
{
    std::cout << "Running X-Macros 'Properties'  example test..." << std::endl;
    
    Properties p;

    // (5) Test all properties
#define X(tp, name, tv) \
    assertEquals(p.get##name(), tp());  \
    p.set##name(tv);                    \
    assertEquals(p.get##name(), tv) 
    GENERATE_PROPS
#undef X

    if (!gErrorCount)
    {
        std::cout << "All tests passed" << std::endl;
   }

    return gErrorCount;
}
