2026-07-21 09:42:30 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| BuilderTest.mqh |
|
|
|
|
|
//| Copyright 2026, MetaQuotes Ltd. |
|
|
|
|
|
//| https://www.mql5.com |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
#property copyright "Copyright 2026, MetaQuotes Ltd."
|
|
|
|
|
#property link "https://www.mql5.com"
|
|
|
|
|
#property strict
|
|
|
|
|
|
|
|
|
|
#ifndef JSONPARSERBYLEO_WF_INC_BUILDERTEST_MQH
|
|
|
|
|
#define JSONPARSERBYLEO_WF_INC_BUILDERTEST_MQH
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Tests de CJsonBuilder (JSON valido) y CJsonBuilderStr (JSON |
|
|
|
|
|
//| doblemente escapado, para meter un JSON como valor string). |
|
|
|
|
|
//| No requieren parser ni fixture: cada test construye su propio |
|
|
|
|
|
//| builder local y compara el string de salida via Build(). |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
#include "Def.mqh"
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
namespace TSN
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
// SECCION 1: CJsonBuilder (JSON valido, escape simple)
|
|
|
|
|
//======================================================================
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 1. Objeto simple con un string |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_SimpleObjString : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_SimpleObj_String"; }
|
|
|
|
|
inline int Importance() const override final { return 95; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilder b;
|
2026-07-21 10:38:19 -05:00
|
|
|
b.Obj();
|
|
|
|
|
b.Key("symbol").ValS("EURUSD").EndObj();
|
2026-07-21 09:42:30 -05:00
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "{\"symbol\":\"EURUSD\"}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 2. Objeto con multiples tipos (int, double, bool, null) |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_MultiTypeObj : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_MultiTypeObj"; }
|
|
|
|
|
inline int Importance() const override final { return 95; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilder b;
|
|
|
|
|
b.Obj();
|
|
|
|
|
b.Key("id").Val(7);
|
|
|
|
|
b.Key("price").Val(1.5, 2);
|
|
|
|
|
b.Key("active").Val(true);
|
|
|
|
|
b.Key("nothing").Null();
|
|
|
|
|
b.EndObj();
|
|
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "{\"id\":7,\"price\":1.50,\"active\":true,\"nothing\":null}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 3. Array simple de enteros |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_ArrayInts : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_Array_Ints"; }
|
|
|
|
|
inline int Importance() const override final { return 90; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilder b;
|
|
|
|
|
b.Arr().Val(1).Val(2).Val(3).EndArr();
|
|
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "[1,2,3]")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 4. Array vacio |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_EmptyArray : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_EmptyArray"; }
|
|
|
|
|
inline int Importance() const override final { return 75; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilder b;
|
|
|
|
|
b.Arr().EndArr();
|
|
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "[]")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 5. Objeto vacio |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_EmptyObj : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_EmptyObj"; }
|
|
|
|
|
inline int Importance() const override final { return 75; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilder b;
|
|
|
|
|
b.Obj().EndObj();
|
|
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "{}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 6. Objeto anidado dentro de objeto |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_NestedObjInObj : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_NestedObjInObj"; }
|
|
|
|
|
inline int Importance() const override final { return 90; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilder b;
|
|
|
|
|
b.Obj();
|
|
|
|
|
b.Key("meta").Obj();
|
|
|
|
|
b.Key("id").Val(1);
|
|
|
|
|
b.EndObj();
|
|
|
|
|
b.EndObj();
|
|
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "{\"meta\":{\"id\":1}}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 7. Array de objetos |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_ArrayOfObjects : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_ArrayOfObjects"; }
|
|
|
|
|
inline int Importance() const override final { return 90; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilder b;
|
|
|
|
|
b.Arr();
|
2026-07-21 10:38:19 -05:00
|
|
|
b.Obj();
|
|
|
|
|
b.Key("id").Val(1).EndObj();
|
|
|
|
|
b.Obj();
|
|
|
|
|
b.Key("id").Val(2).EndObj();
|
2026-07-21 09:42:30 -05:00
|
|
|
b.EndArr();
|
|
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "[{\"id\":1},{\"id\":2}]")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 8. Array anidado (array de arrays) |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_NestedArrays : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_NestedArrays"; }
|
|
|
|
|
inline int Importance() const override final { return 85; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilder b;
|
|
|
|
|
b.Arr();
|
|
|
|
|
b.Arr().Val(1).Val(2).EndArr();
|
|
|
|
|
b.Arr().Val(3).Val(4).EndArr();
|
|
|
|
|
b.EndArr();
|
|
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "[[1,2],[3,4]]")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 9. ValS escapa comillas y backslash correctamente (simple) |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_EscapeQuotesBackslash : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_ValS_EscapeQuotesBackslash"; }
|
|
|
|
|
inline int Importance() const override final { return 90; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilder b;
|
2026-07-21 10:38:19 -05:00
|
|
|
b.Obj();
|
|
|
|
|
b.Key("k").ValS("say \"hi\"\\end").EndObj();
|
2026-07-21 09:42:30 -05:00
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "{\"k\":\"say \\\"hi\\\"\\\\end\"}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 10. ValS escapa newline y tab |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_EscapeNewlineTab : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_ValS_EscapeNewlineTab"; }
|
|
|
|
|
inline int Importance() const override final { return 85; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilder b;
|
2026-07-21 10:38:19 -05:00
|
|
|
b.Obj();
|
|
|
|
|
b.Key("k").ValS("line1\nline2\ttabbed").EndObj();
|
2026-07-21 09:42:30 -05:00
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "{\"k\":\"line1\\nline2\\ttabbed\"}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 11. ValS escapa unicode > 0xFF como \uXXXX |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_EscapeUnicode : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_ValS_EscapeUnicode"; }
|
|
|
|
|
inline int Importance() const override final { return 80; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilder b;
|
|
|
|
|
// U+2514 BOX DRAWINGS LIGHT UP AND RIGHT ("└")
|
2026-07-21 10:38:19 -05:00
|
|
|
b.Obj();
|
|
|
|
|
b.Key("k").ValS("└").EndObj();
|
2026-07-21 09:42:30 -05:00
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "{\"k\":\"\\u2514\"}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 12. Val(double) respeta el numero de decimales (padding) |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_DoublePadding : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_ValDouble_DigitsPadding"; }
|
|
|
|
|
inline int Importance() const override final { return 85; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilder b;
|
2026-07-21 10:38:19 -05:00
|
|
|
b.Obj();
|
|
|
|
|
b.Key("v").Val(20.0, 8).EndObj();
|
2026-07-21 09:42:30 -05:00
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "{\"v\":20.00000000}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 13. Val(double) negativo |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_DoubleNegative : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_ValDouble_Negative"; }
|
|
|
|
|
inline int Importance() const override final { return 80; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilder b;
|
2026-07-21 10:38:19 -05:00
|
|
|
b.Obj();
|
|
|
|
|
b.Key("v").Val(-1.5, 2).EndObj();
|
2026-07-21 09:42:30 -05:00
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "{\"v\":-1.50}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 14. Val(long) con valor grande |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_LongBigValue : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_ValLong_BigValue"; }
|
|
|
|
|
inline int Importance() const override final { return 75; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilder b;
|
2026-07-21 10:38:19 -05:00
|
|
|
b.Obj();
|
|
|
|
|
b.Key("v").Val((long)9223372036854775).EndObj();
|
2026-07-21 09:42:30 -05:00
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "{\"v\":9223372036854775}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 15. Val(int) con cero y negativo |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_IntZeroAndNegative : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_ValInt_ZeroAndNegative"; }
|
|
|
|
|
inline int Importance() const override final { return 75; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilder b;
|
|
|
|
|
b.Arr().Val(0).Val(-42).EndArr();
|
|
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "[0,-42]")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 16. KeyWV / ValSWV -> sin validacion/escape (raw passthrough) |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_RawNoValidation : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_KeyWV_ValSWV_RawPassthrough"; }
|
|
|
|
|
inline int Importance() const override final { return 70; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilder b;
|
2026-07-21 10:38:19 -05:00
|
|
|
b.Obj();
|
|
|
|
|
b.KeyWV("raw_key").ValSWV("raw_value").EndObj();
|
2026-07-21 09:42:30 -05:00
|
|
|
string out = b.Build();
|
|
|
|
|
// Sin escape: se inserta literal, sin procesar caracteres especiales
|
|
|
|
|
if(out != "{\"raw_key\":\"raw_value\"}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 17. ValidJson inserta fragmento crudo sin escapar (JSON valido) |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_ValidJsonFragment : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_ValidJson_RawFragment"; }
|
|
|
|
|
inline int Importance() const override final { return 80; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilder b;
|
2026-07-21 10:38:19 -05:00
|
|
|
b.Obj();
|
|
|
|
|
b.Key("data").ValidJson("{\"nested\":true}").EndObj();
|
2026-07-21 09:42:30 -05:00
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "{\"data\":{\"nested\":true}}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 18. Clear() reinicia el builder correctamente |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_ClearResets : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_Clear_Resets"; }
|
|
|
|
|
inline int Importance() const override final { return 70; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilder b;
|
2026-07-21 10:38:19 -05:00
|
|
|
b.Obj();
|
|
|
|
|
b.Key("a").Val(1).EndObj();
|
2026-07-21 09:42:30 -05:00
|
|
|
b.Clear();
|
2026-07-21 10:38:19 -05:00
|
|
|
b.Obj();
|
|
|
|
|
b.Key("b").Val(2).EndObj();
|
2026-07-21 09:42:30 -05:00
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "{\"b\":2}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s' (deberia no contener residuo de 'a')", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
// SECCION 2: CJsonBuilderStr (JSON doblemente escapado)
|
|
|
|
|
//======================================================================
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 19. Objeto simple con doble escape de comillas |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilderStr_SimpleObjDoubleEscaped : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "BuilderStr_SimpleObj_DoubleEscaped"; }
|
|
|
|
|
inline int Importance() const override final { return 95; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilderStr b;
|
2026-07-21 10:38:19 -05:00
|
|
|
b.Obj();
|
|
|
|
|
b.Key("symbol").ValS("EURUSD").EndObj();
|
2026-07-21 09:42:30 -05:00
|
|
|
string out = b.Build();
|
|
|
|
|
// Cada '"' estructural se emite como \" (escapado una vez extra respecto al builder simple)
|
|
|
|
|
if(out != "{\\\"symbol\\\":\\\"EURUSD\\\"}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 20. ValS escapa backslash+comilla con triple barra |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilderStr_EscapeQuoteTriple : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "BuilderStr_ValS_EscapeQuoteTriple"; }
|
|
|
|
|
inline int Importance() const override final { return 90; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilderStr b;
|
2026-07-21 10:38:19 -05:00
|
|
|
b.Obj();
|
|
|
|
|
b.Key("k").ValS("a\"b").EndObj();
|
2026-07-21 09:42:30 -05:00
|
|
|
string out = b.Build();
|
|
|
|
|
// La comilla dentro del valor -> \\\" (triple barra + comilla)
|
|
|
|
|
if(out != "{\\\"k\\\":\\\"a\\\\\\\"b\\\"}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 21. ValS escapa newline con doble barra (\\n) |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilderStr_EscapeNewlineDouble : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "BuilderStr_ValS_EscapeNewlineDouble"; }
|
|
|
|
|
inline int Importance() const override final { return 85; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilderStr b;
|
2026-07-21 10:38:19 -05:00
|
|
|
b.Obj();
|
|
|
|
|
b.Key("k").ValS("a\nb").EndObj();
|
2026-07-21 09:42:30 -05:00
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "{\\\"k\\\":\\\"a\\\\nb\\\"}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 22. ValS escapa unicode > 0xFF con doble barra (\\uXXXX) |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilderStr_EscapeUnicodeDouble : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "BuilderStr_ValS_EscapeUnicodeDouble"; }
|
|
|
|
|
inline int Importance() const override final { return 80; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilderStr b;
|
2026-07-21 10:38:19 -05:00
|
|
|
b.Obj();
|
|
|
|
|
b.Key("k").ValS("└").EndObj();
|
2026-07-21 09:42:30 -05:00
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "{\\\"k\\\":\\\"\\\\u2514\\\"}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 23. Objeto anidado con CJsonBuilderStr |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilderStr_NestedObj : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "BuilderStr_NestedObj"; }
|
|
|
|
|
inline int Importance() const override final { return 85; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilderStr b;
|
|
|
|
|
b.Obj();
|
|
|
|
|
b.Key("meta").Obj();
|
|
|
|
|
b.Key("id").Val(1);
|
|
|
|
|
b.EndObj();
|
|
|
|
|
b.EndObj();
|
|
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "{\\\"meta\\\":{\\\"id\\\":1}}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 24. Array con CJsonBuilderStr y valores mixtos |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilderStr_ArrayMixedValues : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "BuilderStr_Array_MixedValues"; }
|
|
|
|
|
inline int Importance() const override final { return 80; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilderStr b;
|
2026-07-21 10:38:19 -05:00
|
|
|
b.Arr();
|
|
|
|
|
b.Val(1).Val(true).Null();
|
|
|
|
|
b.ValS("x").EndArr();
|
2026-07-21 09:42:30 -05:00
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "[1,true,null,\\\"x\\\"]")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 25. ValSWV en CJsonBuilderStr -> sigue envolviendo en \" sin |
|
|
|
|
|
//| escapar el contenido interno |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilderStr_ValSWVRaw : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "BuilderStr_ValSWV_RawPassthrough"; }
|
|
|
|
|
inline int Importance() const override final { return 65; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
|
|
|
|
TSN::CJsonBuilderStr b;
|
2026-07-21 10:38:19 -05:00
|
|
|
b.Obj();
|
|
|
|
|
b.Key("k").ValSWV("raw").EndObj();
|
2026-07-21 09:42:30 -05:00
|
|
|
string out = b.Build();
|
|
|
|
|
if(out != "{\\\"k\\\":\\\"raw\\\"}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("obtenido '%s'", out);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 26. Comparativa cruzada: mismo contenido, distinto nivel de |
|
|
|
|
|
//| escape entre CJsonBuilder y CJsonBuilderStr |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CTestBuilder_CrossCompareEscapeLevels : public ICiTest
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
inline string Name() const override final { return "Builder_CrossCompare_EscapeLevels"; }
|
|
|
|
|
inline int Importance() const override final { return 75; }
|
|
|
|
|
bool Run(string &msg) override final
|
|
|
|
|
{
|
2026-07-21 10:38:19 -05:00
|
|
|
TSN::CJsonBuilder simple;
|
2026-07-21 09:42:30 -05:00
|
|
|
TSN::CJsonBuilderStr doubled;
|
|
|
|
|
|
2026-07-21 10:38:19 -05:00
|
|
|
simple.Obj();
|
|
|
|
|
simple.Key("k").ValS("v").EndObj();
|
|
|
|
|
doubled.Obj();
|
|
|
|
|
doubled.Key("k").ValS("v").EndObj();
|
2026-07-21 09:42:30 -05:00
|
|
|
|
|
|
|
|
string out_simple = simple.Build();
|
|
|
|
|
string out_doubled = doubled.Build();
|
|
|
|
|
|
|
|
|
|
if(out_simple != "{\"k\":\"v\"}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("CJsonBuilder produjo '%s', esperado JSON valido simple", out_simple);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if(out_doubled != "{\\\"k\\\":\\\"v\\\"}")
|
|
|
|
|
{
|
|
|
|
|
msg = StringFormat("CJsonBuilderStr produjo '%s', esperado doble escape", out_doubled);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if(out_simple == out_doubled)
|
|
|
|
|
{
|
|
|
|
|
msg = "ambos builders produjeron el mismo string, se esperaba escape distinto";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
#endif // JSONPARSERBYLEO_WF_INC_BUILDERTEST_MQH
|