summaryrefslogtreecommitdiff
path: root/packages/fcl-json
diff options
context:
space:
mode:
authormichael <michael@3ad0048d-3df7-0310-abae-a5850022a9f2>2011-01-05 22:49:00 +0000
committermichael <michael@3ad0048d-3df7-0310-abae-a5850022a9f2>2011-01-05 22:49:00 +0000
commit11b943ac7c21ebedff2987852f9e7deb5c826d6d (patch)
tree1fe42fcf79904132e4f22f1912381e764e92fe5f /packages/fcl-json
parent2611974405dd5619d66e9d33c3ecddd9af426858 (diff)
downloadfpc-11b943ac7c21ebedff2987852f9e7deb5c826d6d.tar.gz
* Support for RTTI streaming
git-svn-id: http://svn.freepascal.org/svn/fpc/trunk@16712 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'packages/fcl-json')
-rw-r--r--packages/fcl-json/src/fpjson.pp22
-rw-r--r--packages/fcl-json/src/fpjsonrtti.pp1014
-rw-r--r--packages/fcl-json/tests/testjson.lpi32
-rw-r--r--packages/fcl-json/tests/testjson.pp2
-rw-r--r--packages/fcl-json/tests/testjsondata.pp36
-rw-r--r--packages/fcl-json/tests/testjsonrtti.pp1770
6 files changed, 2867 insertions, 9 deletions
diff --git a/packages/fcl-json/src/fpjson.pp b/packages/fcl-json/src/fpjson.pp
index 7951564853..591d991d95 100644
--- a/packages/fcl-json/src/fpjson.pp
+++ b/packages/fcl-json/src/fpjson.pp
@@ -382,7 +382,7 @@ Type
// Examine
procedure Iterate(Iterator : TJSONObjectIterator; Data: TObject);
function IndexOf(Item: TJSONData): Integer;
- Function IndexOfName(const AName: TJSONStringType): Integer;
+ Function IndexOfName(const AName: TJSONStringType; CaseInsensitive : Boolean = False): Integer;
// Manipulate
Procedure Clear; override;
function Add(const AName: TJSONStringType; AValue: TJSONData): Integer; overload;
@@ -416,11 +416,13 @@ Type
Function StringToJSONString(const S : TJSONStringType) : TJSONStringType;
Function JSONStringToString(const S : TJSONStringType) : TJSONStringType;
-
+Function JSONTypeName(JSONType : TJSONType) : String;
implementation
+Uses typinfo;
+
Resourcestring
SErrCannotConvertFromNull = 'Cannot convert data from Null value';
SErrCannotConvertToNull = 'Cannot convert data to Null value';
@@ -521,6 +523,11 @@ begin
Result:=Result+Copy(S,J,I-J+1);
end;
+function JSONTypeName(JSONType: TJSONType): String;
+begin
+ Result:=GetEnumName(TypeInfo(TJSONType),Ord(JSONType));
+end;
+
{ TJSONData }
@@ -1316,6 +1323,8 @@ begin
if not (foSingleLineArray in Options) then
Result:=Result+sLineBreak
end;
+ if not (foSingleLineArray in Options) then
+ Result:=Result+IndentString(Options, CurrentIndent);
Result:=Result+']';
end;
@@ -1870,9 +1879,16 @@ begin
Result:=FHash.IndexOf(Item);
end;
-function TJSONObject.IndexOfName(const AName: TJSONStringType): Integer;
+function TJSONObject.IndexOfName(const AName: TJSONStringType; CaseInsensitive : Boolean = False): Integer;
+
begin
Result:=FHash.FindIndexOf(AName);
+ if (Result=-1) and CaseInsensitive then
+ begin
+ Result:=Count-1;
+ While (Result>=0) and (CompareText(Names[Result],AName)<>0) do
+ Dec(Result);
+ end;
end;
procedure TJSONObject.Clear;
diff --git a/packages/fcl-json/src/fpjsonrtti.pp b/packages/fcl-json/src/fpjsonrtti.pp
new file mode 100644
index 0000000000..15f0c46b8c
--- /dev/null
+++ b/packages/fcl-json/src/fpjsonrtti.pp
@@ -0,0 +1,1014 @@
+unit fpjsonrtti;
+
+{$mode objfpc}
+
+interface
+
+uses
+ Classes, SysUtils, typinfo, fpjson, rttiutils, jsonparser;
+
+Type
+
+ TJSONStreamEvent = Procedure (Sender : TObject; AObject : TObject; JSON : TJSONObject) of object;
+ TJSONPropertyEvent = Procedure (Sender : TObject; AObject : TObject; Info : PPropInfo; var Res : TJSONData) of object;
+
+ TJSONStreamOption = (jsoStreamChildren, // If set, children will be streamed in 'Children' Property
+ jsoEnumeratedAsInteger, // Write enumerated as integer. Default is string.
+ jsoSetAsString, // Write Set as a string. Default is an array.
+ jsoSetEnumeratedAsInteger, // Write enumerateds in set array as integers.
+ jsoSetBrackets, // Use brackets when creating set as array
+ jsoComponentsInline, // Always stream components inline. Default is to stream name, unless csSubcomponent in ComponentStyle
+ jsoTStringsAsArray, // Stream TStrings as an array of strings. Associated objects are not streamed.
+ jsoTStringsAsObject, // Stream TStrings as an object : string = { object }
+ jsoDateTimeAsString,
+ jsoUseFormatString); // Use FormatString when creating JSON strings.
+ TJSONStreamOptions = Set of TJSONStreamOption;
+
+ TJSONFiler = Class(TComponent)
+ Protected
+ Procedure Error(Const Msg : String);
+ Procedure Error(Const FMT : String; Args : Array of const);
+ end;
+
+ { TJSONStreamer }
+
+ TJSONStreamer = Class(TJSONFiler)
+ private
+ FAfterStreamObject: TJSONStreamEvent;
+ FBeforeStreamObject: TJSONStreamEvent;
+ FChildProperty: String;
+ FDateTimeFormat: String;
+ FOnStreamProperty: TJSONPropertyEvent;
+ FOptions: TJSONStreamOptions;
+ function GetChildProperty: String;
+ function IsChildStored: boolean;
+ function StreamChildren(AComp: TComponent): TJSONArray;
+ protected
+ function StreamClassProperty(Const AObject: TObject): TJSONData; virtual;
+ Function StreamProperty(Const AObject : TObject; Const PropertyName : String) : TJSONData;
+ Function StreamProperty(Const AObject : TObject; PropertyInfo : PPropInfo) : TJSONData;
+ Function FormatDateProp(const DateTime : TDateTime) : TJSONString;
+ Public
+ Constructor Create(AOwner : TComponent); override;
+ Destructor Destroy;override;
+ //
+ // Basic functions
+ //
+ // Use RTTI to stream object.
+ // If AObject is of type TStrings or TCollection, special treatment occurs:
+ // TStrings results in { Strings: [S,S,S] } or { Strings: { "S1" : O1, "S2" : O2 }} depending on Options.
+ // Collection results in { Items: [I,I,I] }
+ Function ObjectToJSON(Const AObject : TObject) : TJSONObject;
+ // Stream a collection - always returns an array
+ function StreamCollection(Const ACollection: TCollection): TJSONArray;
+ // Stream a TStrings instance as an array
+ function StreamTStringsArray(Const AStrings: TStrings): TJSONArray;
+ // Stream a TStrings instance as an object
+ function StreamTStringsObject(Const AStrings: TStrings): TJSONObject;
+ // Stream a TStrings instance. Takes into account Options.
+ function StreamTStrings(Const AStrings: TStrings): TJSONData;
+ // Stream a variant as JSON.
+ function StreamVariant(const Data: Variant): TJSONData; virtual;
+ //
+ // Some utility functions.
+ //
+ // Call ObjectToJSON and convert result to JSON String.
+ Function ObjectToJSONString(AObject : TObject) : TJSONStringType;
+ // Convert TSTrings to JSON string with array or Object.
+ Function StringsToJSON(Const Strings : TStrings; AsObject : Boolean = False) : TJSONStringType;
+ // Convert collection to JSON string
+ Function CollectionToJSON(Const ACollection : TCollection) : TJSONStringType;
+ // Convert variant to JSON String
+ Function VariantToJSON(Const Data : Variant) : TJSONStringType;
+ Published
+ // Format used when formatting DateTime values. Only used in conjunction with jsoDateTimeToString
+ Property DateTimeFormat : String Read FDateTimeFormat Write FDateTimeFormat;
+ // Options to use when streaming
+ Property Options : TJSONStreamOptions Read FOptions Write FOptions;
+ // Called before streaming an object with ObjectToJSON
+ Property BeforeStreamObject : TJSONStreamEvent Read FBeforeStreamObject Write FBeforeStreamObject;
+ // Called After streaming an object with ObjectToJSON
+ Property AfterStreamObject : TJSONStreamEvent Read FAfterStreamObject Write FAfterStreamObject;
+ // Called whenever a property was streamed. If Res is nil on return, no property is added.
+ Property OnStreamProperty : TJSONPropertyEvent Read FOnStreamProperty Write FOnStreamProperty;
+ // Property name to use when streaming child components. Default is "Children"
+ Property ChildProperty : String Read GetChildProperty Write FChildProperty Stored IsChildStored;
+ end;
+
+ { TJSONDeStreamer }
+ TJSONRestorePropertyEvent = Procedure (Sender : TObject; AObject : TObject; Info : PPropInfo; AValue : TJSONData; Var Handled : Boolean) of object;
+ TJSONPropertyErrorEvent = Procedure (Sender : TObject; AObject : TObject; Info : PPropInfo; AValue : TJSONData; Error : Exception; Var Continue : Boolean) of object;
+ TJSONGetObjectEvent = Procedure (Sender : TOBject; AObject : TObject; Info : PPropInfo; AData : TJSONObject; DataName : TJSONStringType; Var AValue : TObject);
+ TJSONDeStreamer = Class(TJSONFiler)
+ private
+ FAfterReadObject: TJSONStreamEvent;
+ FBeforeReadObject: TJSONStreamEvent;
+ FOnGetObject: TJSONGetObjectEvent;
+ FOnPropError: TJSONpropertyErrorEvent;
+ FOnRestoreProp: TJSONRestorePropertyEvent;
+ procedure DeStreamClassProperty(AObject: TObject; PropInfo: PPropInfo; PropData: TJSONData);
+ protected
+ function GetObject(AInstance : TObject; const APropName: TJSONStringType; D: TJSONObject; PropInfo: PPropInfo): TObject;
+ procedure DoRestoreProperty(AObject: TObject; PropInfo: PPropInfo; PropData: TJSONData); virtual;
+ Function ObjectFromString(Const JSON : TJSONStringType) : TJSONData; virtual;
+ procedure RestoreProperty(AObject: TObject; PropInfo: PPropInfo; PropData: TJSONData);
+ Public
+ Constructor Create(AOwner : TComponent); override;
+ Destructor Destroy; override;
+ // Convert JSON object to properties of AObject
+ Procedure JSONToObject(Const JSON : TJSONStringType; AObject : TObject);
+ Procedure JSONToObject(Const JSON : TJSONObject; AObject : TObject);
+ // Convert JSON object/array to collection.
+ Procedure JSONToCollection(Const JSON : TJSONStringType; ACollection : TCollection);
+ Procedure JSONToCollection(Const JSON : TJSONData; ACollection : TCollection);
+ // Convert JSON array/object/string to TStrings
+ Procedure JSONToStrings(Const JSON : TJSONStringType; AStrings : TSTrings);
+ Procedure JSONToStrings(Const JSON : TJSONData; AStrings : TSTrings);
+ // Convert JSON data to a variant. Supports simple data types and arrays.
+ Function JSONToVariant(Data: TJSONData): Variant;
+ Function JSONToVariant(Data: TJSONStringType): Variant;
+ // Triggered at the start of each call to JSONToObject
+ Property BeforeReadObject : TJSONStreamEvent Read FBeforeReadObject Write FBeforeReadObject;
+ // Triggered at the end of each call to JSONToObject (not if exception happens)
+ Property AfterReadObject : TJSONStreamEvent Read FAfterReadObject Write FAfterReadObject;
+ // Called when a property will be restored. If 'Handled' is True on return, property is considered restored.
+ Property OnRestoreProperty : TJSONRestorePropertyEvent Read FOnRestoreProp Write FOnRestoreProp;
+ // Called when an error occurs when restoring a property. If Continue is False on return, exception is re-raised.
+ Property OnPropertyError : TJSONpropertyErrorEvent Read FOnPropError Write FOnPropError;
+ // Called when a object-typed property must be restored, and the property is Nil. Must return an instance for the property.
+ // Published Properties of the instance will be further restored with available data.
+ Property OngetObject : TJSONGetObjectEvent Read FOnGetObject Write FOnGetObject;
+ end;
+
+ EJSONRTTI = Class(Exception);
+
+
+implementation
+
+uses variants;
+
+ResourceString
+ SErrUnknownPropertyKind = 'Unknown property kind for property : "%s"';
+ SErrUnsupportedPropertyKind = 'Unsupported property kind for property: "%s"';
+ SErrUnsupportedVariantType = 'Unsupported variant type : %d';
+ SErrUnsupportedArrayType = 'JSON array cannot be streamed to object of class "%s"';
+ SErrUnsupportedJSONType = 'Cannot destream object from JSON data of type "%s"';
+ SErrUnsupportedCollectionType = 'Unsupported JSON type for collections: "%s"';
+ SErrUnsupportedCollectionItemType = 'Array element %d is not a valid type for a collection item: "%s"';
+ SErrUnsupportedStringsItemType = 'Array element %d is not a valid type for a stringlist item: "%s"';
+ SErrUnsupportedStringsType = 'Unsupported JSON type for stringlists: "%s"';
+ SErrUnsupportedStringsObjectType = 'Object Element %s is not a valid type for a stringlist object: "%s"';
+ SErrUnSupportedEnumDataType = 'Unsupported JSON type for enumerated property "%s" : "%s"';
+ SErrUnsupportedVariantJSONType = 'Unsupported JSON type for variant value : "%s"';
+ SErrUnsupportedObjectData = 'Unsupported JSON type for object property: "%s"';
+
+{ TStreamChildrenHelper }
+
+Type
+ TSet = set of 0..31; // Used to (de)stream set properties.
+
+ TStreamChildrenHelper = Class
+ Private
+ FChildren : TJSONArray;
+ FStreamer:TJSONStreamer;
+ procedure StreamChild(AChild: TComponent);
+ public
+ Function StreamChildren(AComponent : TComponent; AStreamer : TJSONStreamer): TJSONArray;
+ end;
+
+ THackComponent = Class(TComponent);
+
+{ TJSONDeStreamer }
+
+function TJSONDeStreamer.ObjectFromString(const JSON: TJSONStringType): TJSONData;
+
+begin
+ With TJSONParser.Create(JSON) do
+ try
+ Result:=Parse;
+ finally
+ Free;
+ end;
+end;
+
+constructor TJSONDeStreamer.Create(AOwner: TComponent);
+begin
+ inherited Create(AOwner);
+end;
+
+destructor TJSONDeStreamer.Destroy;
+begin
+ inherited Destroy;
+end;
+
+procedure TJSONDeStreamer.JSONToObject(Const JSON: TJSONStringType; AObject: TObject);
+
+Var
+ D : TJSONData;
+
+begin
+ D:=ObjectFromString(JSON);
+ try
+ If D.JSONType=jtObject then
+ JSONToObject(D as TJSONObject,AObject)
+ else if D.JSONType=jtArray then
+ begin
+ If AObject is TStrings then
+ JSONToStrings(D,AObject as TSTrings)
+ else if AObject is TCollection then
+ JSONTOCollection(D,AObject as TCollection)
+ else
+ Error(SErrUnsupportedArrayType,[AObject.ClassName])
+ end
+ else if (D.JSONType=jtString) and (AObject is TStrings) then
+ JSONToStrings(D,AObject as TStrings)
+ else
+ Error(SErrUnsupportedJSONType,[JSONTypeName(D.JSONType)]);
+ finally
+ FreeAndNil(D);
+ end;
+end;
+
+Function TJSONDeStreamer.JSONToVariant(Data : TJSONData) : Variant;
+
+Var
+ I : integer;
+
+begin
+ Case Data.JSONType of
+ jtNumber :
+ Case TJSONNumber(Data).NumberType of
+ ntFloat : Result:=Data.AsFloat;
+ ntInteger : Result:=Data.AsInteger;
+ ntInt64 : Result:=Data.Asint64;
+ end;
+ jtString :
+ Result:=Data.AsString;
+ jtBoolean:
+ Result:=Data.AsBoolean;
+ jtNull:
+ Result:=Null;
+ jtArray :
+ begin
+ Result:=VarArrayCreate([0,Data.Count-1],varVariant);
+ For I:=0 to Data.Count-1 do
+ Result[i]:=JSONToVariant(Data.Items[i]);
+ end;
+ else
+ Error(SErrUnsupportedVariantJSONType,[GetEnumName(TypeInfo(TJSONType),Ord(Data.JSONType))]);
+ end;
+end;
+
+function TJSONDeStreamer.JSONToVariant(Data: TJSONStringType): Variant;
+
+Var
+ D : TJSONData;
+
+begin
+ D:=ObjectFromString(Data);
+ try
+ Result:=JSONToVariant(D);
+ finally
+ D.Free;
+ end;
+end;
+
+procedure TJSONDeStreamer.DeStreamClassProperty(AObject : TObject;PropInfo : PPropInfo; PropData : TJSONData);
+
+Var
+ O : TObject;
+
+begin
+ O:=GetObjectProp(AObject,PropInfo);
+ If O is TStrings then
+ JSONToStrings(PropData,O as TStrings)
+ else if (O is TCollection) then
+ JSONToCollection(PropData,O as TCollection)
+ else
+ begin
+ If (O=Nil) then
+ begin
+ If (PropData.JSONType=jtString) then
+ O:=GetObject(AObject,PropData.AsString,Nil,PropInfo)
+ else if (PropData.JSONType=jtObject) then
+ O:=GetObject(AObject,'',PropData as TJSONObject,PropInfo)
+ else
+ Error(SErrUnsupportedObjectData,[JsonTypeName(PropData.JSONType){GetEnumName(TypeInfo(TJSONType),Ord(PropData.JSONType))}]);
+ SetObjectProp(AObject,PropInfo,O);
+ end;
+ If (O<>Nil) and (PropData.JSONType=jtObject) then
+ JSONToObject(PropData as TJSONObject,O);
+ end;
+end;
+
+procedure TJSONDeStreamer.RestoreProperty(AObject : TObject;PropInfo : PPropInfo; PropData : TJSONData);
+
+Var
+ B : Boolean;
+
+begin
+ try
+ B:=Not Assigned(FOnRestoreProp);
+ If Not B then
+ begin
+ FOnRestoreProp(Self,AObject,PropInfo,PropData,B);
+ If B then
+ exit;
+ end;
+ DoRestoreProperty(AObject,PropInfo,PropData);
+ except
+ On E : Exception do
+ If Assigned(FOnPropError) then
+ begin
+ B:=False;
+ FOnPropError(Self,AObject,PropInfo,PropData,E,B);
+ If Not B then
+ Raise;
+ end;
+ end;
+end;
+
+procedure TJSONDeStreamer.DoRestoreProperty(AObject : TObject;PropInfo : PPropInfo; PropData : TJSONData);
+
+Var
+ PI : PPropInfo;
+ TI : PTypeInfo;
+ I,J,S : Integer;
+ D : Double;
+ A : TJSONArray;
+ JS : TJSONStringType;
+begin
+ PI:=PropInfo;
+ TI:=PropInfo^.PropType;
+ case TI^.Kind of
+ tkUnknown :
+ Error(SErrUnknownPropertyKind,[PI^.Name]);
+ tkInteger :
+ SetOrdProp(AObject,PI,PropData.AsInteger);
+ tkInt64 :
+ SetOrdProp(AObject,PI,PropData.AsInt64);
+ tkEnumeration :
+ begin
+ if (PropData.JSONType=jtNumber) then
+ I:=PropData.AsInteger
+ else if PropData.JSONType=jtString then
+ I:=GetEnumValue(TI,PropData.AsString)
+ else
+ Error(SErrUnSupportedEnumDataType,[PI^.Name,GetEnumName(TypeInfo(TJSONType),Ord(PropData.JSONType))]);
+ SetOrdProp(AObject,PI,I);
+ end;
+ tkFloat :
+ begin
+ if (TI=TypeInfo(TDateTime)) and (PropData.JSONType=jtString) then
+ SetFloatProp(AObject,PI,StrToDateTime(PropData.AsString))
+ else
+ SetFloatProp(AObject,PI,PropData.AsFloat)
+ end;
+ tkSet :
+ If PropData.JSONType=jtString then
+ SetSetProp(AObject,PI,PropData.AsString)
+ else if (PropData.JSONType=jtArray) then
+ begin
+ A:=PropData as TJSONArray;
+ TI:=GetTypeData(TI)^.CompType;
+ S:=0;
+ For I:=0 to A.Count-1 do
+ begin
+ if A.types[i]=jtNumber then
+ J:=A.Integers[i]
+ else
+ J:=GetEnumValue(TI,A.strings[i]);
+ TSet(S):=TSet(S)+[j];
+ end;
+ SetOrdProp(AObject,PI,S);
+ end;
+ tkChar:
+ begin
+ JS:=PropData.AsString;
+ If (JS<>'') then
+ SetOrdProp(AObject,PI,Ord(JS[1]));
+ end;
+ tkSString,
+ tkLString,
+ tkAString:
+ SetStrProp(AObject,PI,PropData.AsString);
+ tkWString :
+ SetWideStrProp(AObject,PI,PropData.AsString);
+ tkVariant:
+ SetVariantProp(AObject,PI,JSONToVariant(PropData));
+ tkClass:
+ DeStreamClassProperty(AObject,PI,PropData);
+ tkWChar :
+ begin
+ JS:=PropData.asString;
+ If (JS<>'') then
+ SetOrdProp(AObject,PI,Ord(JS[1]));
+ end;
+ tkBool :
+ SetOrdProp(AObject,PI,Ord(PropData.AsBoolean));
+ tkQWord :
+ SetOrdProp(AObject,PI,Trunc(PropData.AsFloat));
+ tkObject,
+ tkArray,
+ tkRecord,
+ tkInterface,
+ tkDynArray,
+ tkInterfaceRaw,
+ tkProcVar,
+ tkMethod :
+ Error(SErrUnsupportedPropertyKind,[PI^.Name]);
+ tkUString :
+ SetUnicodeStrProp(AObject,PI,PropData.AsString);
+ tkUChar:
+ begin
+ JS:=PropData.asString;
+ If (JS<>'') then
+ SetOrdProp(AObject,PI,Ord(JS[1]));
+ end;
+ end;
+end;
+
+procedure TJSONDeStreamer.JSONToObject(Const JSON: TJSONObject; AObject: TObject);
+Var
+ I,J : Integer;
+ PIL : TPropInfoList;
+
+begin
+ If Assigned(FBeforeReadObject) then
+ FBeforeReadObject(Self,AObject,JSON);
+ If (AObject is TStrings) then
+ JSONToStrings(JSON,AObject as TStrings)
+ else If (AObject is TCollection) then
+ JSONToCollection(JSON, AObject as TCollection)
+ else
+ begin
+ Pil:=TPropInfoList.Create(AObject,tkProperties);
+ try
+ For I:=0 to PIL.Count-1 do
+ begin
+ J:=JSON.IndexOfName(Pil.Items[i]^.Name);
+ If (J<>-1) then
+ RestoreProperty(AObject,PIL.Items[i],JSON.Items[J]);
+ end;
+ finally
+ FreeAndNil(PIL);
+ end;
+ end;
+ If Assigned(FAfterReadObject) then
+ FAfterReadObject(Self,AObject,JSON)
+end;
+
+procedure TJSONDeStreamer.JSONToCollection(const JSON: TJSONStringType;
+ ACollection: TCollection);
+Var
+ D : TJSONData;
+
+begin
+ D:=ObjectFromString(JSON);
+ try
+ JSONToCollection(D,ACollection);
+ finally
+ D.Free;
+ end;
+end;
+
+procedure TJSONDeStreamer.JSONToCollection(const JSON: TJSONData;
+ ACollection: TCollection);
+
+Var
+ I : integer;
+ A : TJSONArray;
+ O : TJSONObject;
+
+begin
+ If (JSON.JSONType=jtArray) then
+ A:=JSON As TJSONArray
+ else if JSON.JSONType=jtObject then
+ A:=(JSON as TJSONObject).Arrays['Items']
+ else
+ Error(SErrUnsupportedCollectionType,[JSONTypeName(JSON.JSONType)]);
+ ACollection.Clear;
+ For I:=0 to A.Count-1 do
+ If (A.Types[i]<>jtObject) then
+ Error(SErrUnsupportedCollectionItemType,[I,JSONTypeName(A.Types[I])])
+ else
+ JSONToObject(A.Objects[i],ACollection.Add);
+end;
+
+procedure TJSONDeStreamer.JSONToStrings(const JSON: TJSONStringType;
+ AStrings: TSTrings);
+Var
+ D : TJSONData;
+
+begin
+ D:=ObjectFromString(JSON);
+ try
+ JSONToStrings(D,AStrings);
+ finally
+ D.Free;
+ end;
+end;
+
+Function TJSONDeStreamer.GetObject(AInstance : TObject; Const APropName : TJSONStringType; D : TJSONObject; PropInfo : PPropInfo) : TObject;
+
+Var
+ C : TClass;
+
+begin
+ Result:=Nil;
+ If Assigned(FOnGetObject) then
+ FOnGetObject(Self,AInstance,PropInfo,D,APropName,Result);
+ If (Result=Nil) and (AInstance is TComponent) and Assigned(PropInfo) then
+ begin
+ C:=GetTypeData(Propinfo^.PropType)^.ClassType;
+ If C.InheritsFrom(TComponent) then
+ Result:=TComponentClass(C).Create(TComponent(AInstance));
+ end;
+end;
+
+procedure TJSONDeStreamer.JSONToStrings(const JSON: TJSONData;
+ AStrings: TSTrings);
+
+Var
+ O : TJSONObject;
+ D : TJSONData;
+ I : Integer;
+ IO : TObject;
+ N : TJSONStringType;
+
+begin
+ Case JSON.JSONType of
+ jtString:
+ AStrings.Text:=JSON.AsString;
+ jtArray:
+ begin
+ AStrings.Clear;
+ For I:=0 to JSON.Count-1 do
+ begin
+ if not (JSON.Items[i].JSONType=jtString) then
+ Error(SErrUnsupportedStringsItemType,[i,JSONTypeName(JSON.Items[i].JSONType)]);
+ AStrings.Add(JSON.Items[i].AsString);
+ end;
+ end;
+ jtObject:
+ begin
+ O:=JSON As TJSONObject;
+ If (O.Count=1) and (O.Names[0]='Strings') and (O.Items[0].JSONType=jtArray) then
+ JSONToStrings(O.Items[0],AStrings)
+ else
+ begin
+ AStrings.Clear;
+ For I:=0 to O.Count-1 do
+ begin
+ D:=O.Items[i];
+ N:=O.Names[i];
+ If D.JSONType=jtNull then
+ IO:=Nil
+ else if D.JSONType=jtObject then
+ IO:=GetObject(AStrings,N,TJSONOBject(D),Nil)
+ else
+ Error(SErrUnsupportedStringsObjectType,[D,JSONTypeName(D.JSONType)]);
+ AStrings.AddObject(O.Names[i],IO);
+ end;
+ end;
+ end;
+ else
+ Error(SErrUnsupportedStringsType,[JSONTypeName(JSON.JSONType)]);
+ end;
+end;
+
+Procedure TStreamChildrenHelper.StreamChild(AChild : TComponent);
+
+begin
+ FChildren.Add(FStreamer.ObjectToJSON(AChild));
+end;
+
+Function TStreamChildrenHelper.StreamChildren(AComponent : TComponent; AStreamer : TJSONStreamer): TJSONArray;
+
+begin
+ FStreamer:=AStreamer;
+ Result:=TJSONArray.Create;
+ try
+ FChildren:=Result;
+ THackComponent(AComponent).GetChildren(@StreamChild,AComponent);
+ except
+ FreeAndNil(Result);
+ Raise;
+ end;
+end;
+
+{ TJSONFiler }
+
+procedure TJSONFiler.Error(Const Msg: String);
+begin
+ Raise EJSONRTTI.Create(Name+' : '+Msg);
+end;
+
+procedure TJSONFiler.Error(Const FMT: String; Args: array of const);
+begin
+ Raise EJSONRTTI.CreateFmt(Name+' : '+FMT,Args);
+end;
+
+{ TJSONStreamer }
+
+constructor TJSONStreamer.Create(AOwner: TComponent);
+begin
+ Inherited;
+end;
+
+destructor TJSONStreamer.Destroy;
+begin
+ Inherited;
+end;
+
+
+Function TJSONStreamer.StreamChildren(AComp : TComponent) : TJSONArray;
+
+begin
+ With TStreamChildrenHelper.Create do
+ try
+ Result:=StreamChildren(AComp,Self);
+ finally
+ Free;
+ end;
+end;
+
+function TJSONStreamer.GetChildProperty: String;
+begin
+ Result:=FChildProperty;
+ If (Result='') then
+ Result:='Children';
+end;
+
+function TJSONStreamer.IsChildStored: boolean;
+begin
+ Result:=(GetChildProperty<>'Children');
+end;
+
+function TJSONStreamer.ObjectToJSON(Const AObject: TObject): TJSONObject;
+
+Var
+ PIL : TPropInfoList;
+ PD : TJSONData;
+ I : Integer;
+
+begin
+ Result:=Nil;
+ If (AObject=Nil) then
+ Exit;
+ Result:=TJSONObject.Create;
+ try
+ If Assigned(FBeforeStreamObject) then
+ FBeforeStreamObject(Self,AObject,Result);
+ If AObject is TStrings then
+ Result.Add('Strings',StreamTStrings(Tstrings(AObject)))
+ else If AObject is TCollection then
+ Result.Add('Items',StreamCollection(TCollection(AObject)))
+ else
+ begin
+ PIL:=TPropInfoList.Create(AObject,tkProperties);
+ try
+ For I:=0 to PIL.Count-1 do
+ begin
+ PD:=StreamProperty(AObject,PIL.Items[i]);
+ If (PD<>Nil) then
+ Result.Add(PIL.Items[I]^.Name,PD);
+ end;
+ finally
+ FReeAndNil(Pil);
+ end;
+ If (jsoStreamChildren in Options) and (AObject is TComponent) then
+ Result.Add(ChildProperty,StreamChildren(TComponent(AObject)));
+ If Assigned(FAfterStreamObject) then
+ FAfterStreamObject(Self,AObject,Result);
+ end;
+ except
+ FreeAndNil(Result);
+ Raise;
+ end;
+end;
+
+function TJSONStreamer.StreamProperty(Const AObject: TObject; Const PropertyName : String): TJSONData;
+
+begin
+ Result:=StreamProperty(AObject,GetPropInfo(AObject,PropertyName));
+end;
+
+Function TJSONStreamer.StreamVariant(Const Data : Variant): TJSONData;
+
+Var
+ A : TJSONArray;
+ I : Integer;
+
+begin
+ Result:=Nil;
+ If VarIsArray(Data) then
+ begin
+ A:=TJSONArray.Create;
+ try
+ For I:=VarArrayLowBound(Data,1) to VarArrayHighBound(Data,1) do
+ A.Add(StreamVariant(Data[i]));
+ except
+ FreeAndNil(A);
+ Raise;
+ end;
+ Exit(A);
+ end;
+ If VarIsEmpty(Data) or VarisNull(Data) or (Data=UnAssigned) then
+ Exit(TJSONNull.Create);
+ Case VarType(Data) of
+ varshortint,
+ varbyte,
+ varword,
+ varsmallint,
+ varinteger :
+ Result:=TJSONIntegerNumber.Create(Data);
+ varlongword,
+ varint64 :
+ Result:=TJSONInt64Number.Create(Data);
+ vardecimal,
+ varqword,
+ varsingle,
+ vardouble,
+ varCurrency :
+ Result:=TJSONFloatNumber.Create(Data);
+ varString,
+ varolestr :
+ Result:=TJSONString.Create(Data);
+ varboolean :
+ Result:=TJSONBoolean.Create(Data);
+ varDate :
+ if jsoDateTimeAsString in Options then
+ Result:=FormatDateProp(Data)
+ else
+ Result:=TJSONFloatNumber.Create(Data);
+ else
+ Error(SErrUnsupportedVariantType,[VarType(Data)])
+ end;
+end;
+
+function TJSONStreamer.ObjectToJSONString(AObject: TObject): TJSONStringType;
+
+Var
+ O : TJSONData;
+
+begin
+ O:=ObjectToJSON(AObject);
+ try
+ if (jsoUseFormatString in Options) then
+ Result:=O.FormatJSON()
+ else
+ Result:=O.AsJSON;
+ finally
+ FreeAndNil(O);
+ end;
+end;
+
+function TJSONStreamer.StringsToJSON(Const Strings: TStrings; AsObject: Boolean = False): TJSONStringType;
+
+Var
+ D : TJSONData;
+
+begin
+ If ASObject then
+ D:=StreamTSTringsObject(Strings)
+ else
+ D:=StreamTStringsArray(Strings);
+ try
+ if (jsoUseFormatString in Options) then
+ Result:=D.FormatJSON
+ else
+ Result:=D.AsJSON;
+ finally
+ FreeAndNil(D);
+ end;
+end;
+
+function TJSONStreamer.CollectionToJSON(const ACollection: TCollection
+ ): TJSONStringType;
+
+Var
+ D : TJSONArray;
+
+begin
+ D:=StreamCollection(ACollection);
+ try
+ if (jsoUseFormatString in Options) then
+ Result:=D.FormatJSON()
+ else
+ Result:=D.AsJSON;
+ finally
+ FreeAndNil(D);
+ end;
+end;
+
+function TJSONStreamer.VariantToJSON(const Data: Variant): TJSONStringType;
+
+Var
+ D : TJSONData;
+
+begin
+ D:=StreamVariant(Data);
+ try
+ if (jsoUseFormatString in Options) then
+ Result:=D.FormatJSON()
+ else
+ Result:=D.AsJSON;
+ finally
+ FreeAndNil(D);
+ end;
+end;
+
+Function TJSONStreamer.StreamTStringsArray(Const AStrings : TStrings) : TJSONArray;
+
+Var
+ I : Integer;
+
+begin
+ Result:=TJSONArray.Create;
+ try
+ For I:=0 to AStrings.Count-1 do
+ Result.Add(AStrings[i]);
+ except
+ FreeAndNil(Result);
+ Raise;
+ end;
+end;
+
+function TJSONStreamer.StreamTStringsObject(Const AStrings: TStrings): TJSONObject;
+
+Var
+ I : Integer;
+ O : TJSONData;
+
+begin
+ Result:=TJSONObject.Create;
+ try
+ For I:=0 to AStrings.Count-1 do
+ begin
+ O:=ObjectToJSON(AStrings.Objects[i]);
+ If O=Nil then
+ O:=TJSONNull.Create;
+ Result.Add(AStrings[i],O);
+ end;
+ except
+ FreeAndNil(Result);
+ Raise;
+ end;
+end;
+
+function TJSONStreamer.StreamTStrings(Const AStrings: TStrings): TJSONData;
+begin
+ If jsoTStringsAsArray in Options then
+ Result:=StreamTStringsArray(AStrings)
+ else If jsoTStringsAsObject in Options then
+ Result:=StreamTStringsObject(AStrings)
+ else
+ Result:=TJSONString.Create(AStrings.Text);
+end;
+
+
+Function TJSONStreamer.StreamCollection(Const ACollection : TCollection) : TJSONArray;
+
+Var
+ I : Integer;
+
+begin
+ Result:=TJSONArray.Create;
+ try
+ For I:=0 to ACollection.Count-1 do
+ Result.Add(ObjectToJSON(ACollection.Items[i]));
+ except
+ FreeAndNil(Result);
+ Raise;
+ end;
+end;
+
+Function TJSONStreamer.StreamClassProperty(Const AObject : TObject): TJSONData;
+
+Var
+ C : TCollection;
+ I : integer;
+
+begin
+ Result:=Nil;
+ If (AObject=Nil) then
+ Result:=TJSONNull.Create()
+ else if (AObject is TComponent) then
+ begin
+ if (csSubComponent in TComponent(AObject).ComponentStyle) or (jsoComponentsInline in Options) then
+ Result:=ObjectToJSON(AObject)
+ else
+ Result:=TJSONString.Create(TComponent(AObject).Name);
+ end
+ else if (AObject is TStrings) then
+ Result:=StreamTStrings(TStrings(AObject))
+ else if (AObject is TCollection) then
+ Result:=StreamCollection(TCollection(Aobject))
+ else // Normally, this is only TPersistent.
+ Result:=ObjectToJSON(AObject);
+end;
+
+function TJSONStreamer.StreamProperty(Const AObject: TObject; PropertyInfo: PPropInfo): TJSONData;
+
+Var
+ PI : PPropInfo;
+ PT : PTypeInfo;
+ S,I : integer;
+
+begin
+ Result:=Nil;
+ PI:=PropertyInfo;
+ PT:=PI^.PropType;
+ Case PT^.Kind of
+ tkUnknown :
+ Error(SErrUnknownPropertyKind,[PI^.Name]);
+ tkInteger :
+ Result:=TJSONIntegerNumber.Create(GetOrdProp(AObject,PI));
+ tkEnumeration :
+ if jsoEnumeratedAsInteger in Options then
+ Result:=TJSONIntegerNumber.Create(GetOrdProp(AObject,PI))
+ else
+ Result:=TJSONString.Create(GetEnumName(PT,GetOrdProp(AObject,PI)));
+ tkFloat :
+ if (PT=TypeInfo(TDateTime)) and (jsoDateTimeAsString in Options) then
+ Result:=FormatDateProp(GetFloatProp(AObject,PI))
+ else
+ Result:=TJSONFloatNumber.Create(GetFloatProp(AObject,PI));
+ tkSet :
+ If jsoSetAsString in Options then
+ Result:=TJSONString.Create(GetSetProp(AObject,PI,jsoSetBrackets in Options))
+ else
+ begin
+ PT:=GetTypeData(PT)^.CompType;
+ S:=GetOrdProp(AObject,PI);
+ Result:=TJSONArray.Create;
+ try
+ for i:=0 to 31 do
+ if (i in TSet(S)) then
+ if jsoSetEnumeratedAsInteger in Options then
+ TJSONArray(Result).Add(i)
+ else
+ TJSONArray(Result).Add(GetEnumName(PT, i));
+ except
+ FreeAndNil(Result);
+ Raise;
+ end;
+ end;
+ tkChar:
+ Result:=TJSONString.Create(Char(GetOrdProp(AObject,PI)));
+ tkSString,
+ tkLString,
+ tkAString:
+ Result:=TJSONString.Create(GetStrProp(AObject,PI));
+ tkWString :
+ Result:=TJSONString.Create(GetWideStrProp(AObject,PI));
+ tkVariant:
+ Result:=StreamVariant(GetVariantProp(AObject,PI));
+ tkClass:
+ Result:=StreamClassProperty(GetObjectProp(AObject,PI));
+ tkWChar :
+ Result:=TJSONString.Create(WideChar(GetOrdProp(AObject,PI)));
+ tkBool :
+ Result:=TJSONBoolean.Create(GetOrdProp(AObject,PropertyInfo)<>0);
+ tkInt64 :
+ Result:=TJSONInt64Number.Create(GetOrdProp(AObject,PropertyInfo));
+ tkQWord :
+ Result:=TJSONFloatNumber.Create(GetOrdProp(AObject,PropertyInfo));
+ tkObject,
+ tkArray,
+ tkRecord,
+ tkInterface,
+ tkDynArray,
+ tkInterfaceRaw,
+ tkProcVar,
+ tkMethod :
+ Error(SErrUnsupportedPropertyKind,[PI^.Name]);
+ tkUString :
+ Result:=TJSONString.Create(GetWideStrProp(AObject,PI));
+ tkUChar:
+ Result:=TJSONString.Create(UnicodeChar(GetOrdProp(AObject,PI)));
+ end;
+ If Assigned(FOnStreamProperty) then
+ FOnStreamProperty(Self,AObject,PI,Result);
+end;
+
+function TJSONStreamer.FormatDateProp(Const DateTime: TDateTime): TJSONString;
+
+Var
+ S: String;
+
+begin
+ if (DateTimeFormat<>'') then
+ S:=FormatDateTime(DateTimeFormat,DateTime)
+ else if Frac(DateTime)=0 then
+ S:=DateToStr(DateTime)
+ else if Trunc(DateTime)=0 then
+ S:=TimeToStr(DateTime)
+ else
+ S:=DateTimeToStr(DateTime);
+ Result:=TJSONString.Create(S);
+end;
+
+end.
+
diff --git a/packages/fcl-json/tests/testjson.lpi b/packages/fcl-json/tests/testjson.lpi
index 601c243740..9d9fb168ca 100644
--- a/packages/fcl-json/tests/testjson.lpi
+++ b/packages/fcl-json/tests/testjson.lpi
@@ -1,18 +1,20 @@
<?xml version="1.0"?>
<CONFIG>
<ProjectOptions>
- <Version Value="8"/>
+ <Version Value="9"/>
<General>
<Flags>
<LRSInOutputDirectory Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
- <TargetFileExt Value=""/>
</General>
<VersionInfo>
- <StringTable Comments="" CompanyName="" FileDescription="" FileVersion="0.0.0.0" InternalName="" LegalCopyright="" LegalTrademarks="" OriginalFilename="" ProductName="" ProductVersion=""/>
+ <StringTable ProductVersion=""/>
</VersionInfo>
+ <BuildModes Count="1">
+ <Item1 Name="default" Default="True"/>
+ </BuildModes>
<PublishOptions>
<Version Value="2"/>
<IgnoreBinaries Value="False"/>
@@ -22,6 +24,7 @@
<RunParams>
<local>
<FormatVersion Value="1"/>
+ <CommandLineParams Value="--format=plain --suite=TCJSONStreamer"/>
<LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
</local>
</RunParams>
@@ -39,7 +42,7 @@
<PackageName Value="FCL"/>
</Item4>
</RequiredPackages>
- <Units Count="3">
+ <Units Count="5">
<Unit0>
<Filename Value="testjson.pp"/>
<IsPartOfProject Value="True"/>
@@ -55,19 +58,38 @@
<IsPartOfProject Value="True"/>
<UnitName Value="testjsondata"/>
</Unit2>
+ <Unit3>
+ <Filename Value="testjsonrtti.pp"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="testjsonrtti"/>
+ </Unit3>
+ <Unit4>
+ <Filename Value="../src/fpjsonrtti.pp"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="fpjsonrtti"/>
+ </Unit4>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="9"/>
<SearchPaths>
- <OtherUnitFiles Value="../src/"/>
+ <OtherUnitFiles Value="../src"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<UseAnsiStrings Value="False"/>
</SyntaxOptions>
</Parsing>
+ <Linking>
+ <Debugging>
+ <GenerateDebugInfo Value="True"/>
+ <UseHeaptrc Value="True"/>
+ </Debugging>
+ </Linking>
<Other>
+ <CompilerMessages>
+ <UseMsgFile Value="True"/>
+ </CompilerMessages>
<CompilerPath Value="$(CompPath)"/>
</Other>
</CompilerOptions>
diff --git a/packages/fcl-json/tests/testjson.pp b/packages/fcl-json/tests/testjson.pp
index 67476fda04..e2e430b327 100644
--- a/packages/fcl-json/tests/testjson.pp
+++ b/packages/fcl-json/tests/testjson.pp
@@ -18,7 +18,7 @@ program testjson;
uses
Classes, consoletestrunner, testjsondata, testjsonparser,
- fpcunitconsolerunner;
+ fpcunitconsolerunner, testjsonrtti, fpjsonrtti;
type
{ TLazTestRunner }
TMyTestRunner = class(TTestRunner)
diff --git a/packages/fcl-json/tests/testjsondata.pp b/packages/fcl-json/tests/testjsondata.pp
index 32b89c0877..644509d667 100644
--- a/packages/fcl-json/tests/testjsondata.pp
+++ b/packages/fcl-json/tests/testjsondata.pp
@@ -194,6 +194,7 @@ type
procedure TestExtract;
Procedure TestNonExistingAccessError;
Procedure TestFormat;
+ Procedure TestFind;
end;
@@ -1968,6 +1969,41 @@ begin
end;
end;
+procedure TTestObject.TestFind;
+
+Const
+ A = 'A';
+ S = 'A string';
+ B = 'a';
+ S2 = 'Another string';
+ C = 'c';
+ S3 = 'Yet Another string';
+
+Var
+ J : TJSONObject;
+
+begin
+ J:=TJSONObject.Create([A,S,B,S2,C,S3]);
+ try
+ TestJSONType(J,jtObject);
+ TestIsNull(J,False);
+ TestItemCount(J,3);
+ TestJSONType(J[A],jtString);
+ TestJSONType(J[B],jtString);
+ TestJSON(J,'{ "A" : "'+S+'", "a" : "'+S2+'", "c" : "'+S3+'" }');
+ AssertEquals('Nonexisting, case sensitive',-1,J.IndexOfName('D'));
+ AssertEquals('Nonexisting, case insensitive',-1,J.IndexOfName('D',True));
+ AssertEquals('1 Existing , case sensitive',0,J.IndexOfName(A));
+ AssertEquals('2 Existing exact match, case insensitive',0,J.IndexOfName(A,true));
+ AssertEquals('3 Existing , case sensitive',1,J.IndexOfName(B));
+ AssertEquals('4 Existing exact match, case insensitive',1,J.IndexOfName(B,true));
+ AssertEquals('5 Existing , case sensitive again',2,J.IndexOfName(C));
+ AssertEquals('6 Existing case-insensitive match, case insensitive',2,J.IndexOfName(Uppercase(C),true));
+ finally
+ FreeAndNil(J);
+ end;
+end;
+
procedure TTestObject.TestCreateString;
diff --git a/packages/fcl-json/tests/testjsonrtti.pp b/packages/fcl-json/tests/testjsonrtti.pp
new file mode 100644
index 0000000000..01ffa7da76
--- /dev/null
+++ b/packages/fcl-json/tests/testjsonrtti.pp
@@ -0,0 +1,1770 @@
+unit testjsonrtti;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, fpcunit, testutils, testregistry, typinfo, fpjson,
+ testcomps, testjsondata, fpjsonrtti;
+
+type
+
+ { TCJSONStreamer }
+
+ TCJSONStreamer = class(TTestJSON)
+ private
+ FRJ : TJSONStreamer;
+ FSR : TJSONObject;
+ FToFree : TObject;
+ FCalled : Boolean;
+ procedure DoStreamProperty1(Sender: TObject; AObject: TObject; Info: PPropInfo; var Res: TJSONData);
+ protected
+ procedure SetUp; override;
+ procedure TearDown; override;
+ Procedure AssertEquals(AMessage : String; Expected,Actual : TJSONType); overload;
+ Procedure AssertPropCount(ACount : Integer);
+ Function AssertProperty(APropName : String; AType : TJSONType) : TJSONData;
+ Procedure AssertProp(APropName : String; AValue : Boolean);
+ Procedure AssertProp(APropName : String; AValue : Integer);
+ procedure AssertProp(APropName : String; AValue: String);
+ procedure AssertProp(APropName : String; AValue: TJSONFloat);
+ procedure AssertProp(APropName : String; AValue : Array of String);
+ procedure AssertProp(APropName : String; AValue : Array of Integer);
+ function CreateVariantComp : TVariantComponent;
+ procedure AssertNullProp(APropName : String);
+ Function AssertObjectProp(APropName : String) : TJSONObject;
+ Function AssertArrayProp(APropName : String) : TJSONArray;
+ Function StreamObject(AObject : TObject) : TJSONObject;
+ Property RJ : TJSONStreamer read FRJ;
+ Property SR : TJSONObject Read FSR Write FSR;
+ published
+ procedure TestNil;
+ procedure TestEmpty;
+ procedure TestEmptyComponent;
+ procedure TestWriteBoolean;
+ procedure TestWriteInteger;
+ procedure TestWriteString;
+ procedure TestWriteFloat;
+ procedure TestWriteFloat2;
+ procedure TestWriteFloat3;
+ procedure TestWriteFloat4;
+ procedure TestWriteFloat5;
+ procedure TestEnum1;
+ procedure TestEnum2;
+ Procedure TestSet1;
+ Procedure TestSet2;
+ Procedure TestSet3;
+ Procedure TestSet4;
+ Procedure TestObjectNil;
+ Procedure TestComponentProp1;
+ Procedure TestComponentProp2;
+ Procedure TestCollectionProp1;
+ Procedure TestCollectionProp2;
+ Procedure TestPersistentProp1;
+ Procedure TestStringsProp1;
+ Procedure TestStringsProp2;
+ procedure TestStringsProp3;
+ procedure TestStringsProp4;
+ procedure TestStringsArray;
+ procedure TestStringsObject;
+ procedure TestStringsStream1;
+ procedure TestStringsStream2;
+ procedure TestStringsStream3;
+ procedure TestStringsStream4;
+ procedure TestStringsStream5;
+ procedure TestCollectionStream;
+ procedure TestCollectionStream2;
+ procedure TestOnStreamProperty;
+ Procedure TestDateTimeProp;
+ Procedure TestDateTimeProp2;
+ Procedure TestDateTimeProp3;
+ procedure TestDateTimeProp4;
+ procedure TestDateTimeProp5;
+ procedure TestDateTimeProp6;
+ procedure TestDateTimeProp7;
+ Procedure TestVariantShortint;
+ Procedure TestVariantbyte;
+ Procedure TestVariantword;
+ Procedure TestVariantsmallint;
+ Procedure TestVariantinteger;
+ Procedure TestVariantlongword;
+ Procedure TestVariantint64;
+ Procedure TestVariantqword;
+ Procedure TestVariantsingle;
+ Procedure TestVariantdouble;
+ Procedure TestVariantCurrency;
+ Procedure TestVariantString;
+ Procedure TestVariantolestr;
+ Procedure TestVariantboolean;
+ Procedure TestVariantDate;
+ procedure TestVariantDate2;
+ Procedure TestVariantArray;
+ Procedure TestMultipleProps;
+ Procedure TestObjectToJSONString;
+ Procedure TestStringsToJSONString;
+ Procedure TestCollectionToJSONString;
+ Procedure TestChildren;
+ Procedure TestChildren2;
+ end;
+
+ { TCJSONDeStreamer }
+
+ TCJSONDeStreamer = class(TTestJSON)
+ private
+ FDS : TJSONDeStreamer;
+ FJD : TJSONData;
+ FToFree : TObject;
+ FCalled : Boolean;
+ procedure DeStream(JSON: TJSONStringType; AObject: TObject);
+ procedure DeStream(JSON: TJSONObject; AObject: TObject);
+ protected
+ procedure SetUp; override;
+ procedure TearDown; override;
+ Procedure AssertVarType(Msg : String; AVarType : TVarType; Const Variant : Variant);
+ Property DS : TJSONDeStreamer Read FDS;
+ Property JD : TJSONData Read FJD Write FJD;
+ Property Tofree : TObject Read FToFree Write FToFree;
+ published
+ Procedure TestVariantInteger;
+ Procedure TestVariantFloat;
+ Procedure TestVariantInt64;
+ Procedure TestVariantBoolean;
+ Procedure TestVariantNull;
+ Procedure TestVariantString;
+ Procedure TestVariantArray;
+ procedure TestEmpty;
+ procedure TestBoolean;
+ procedure TestInteger;
+ procedure TestString;
+ procedure TestFloat;
+ procedure TestFloat2;
+ procedure TestFloat3;
+ procedure TestFloat4;
+ procedure TestFloat5;
+ procedure TestEnum1;
+ procedure TestEnum2;
+ Procedure TestSet1;
+ Procedure TestSet2;
+ Procedure TestSet3;
+ Procedure TestSet4;
+ Procedure TestVariantProp;
+ procedure TestCollection;
+ procedure TestCollection2;
+ procedure TestCollection3;
+ procedure TestCollection4;
+ procedure TestCollection5;
+ procedure TestCollection6;
+ procedure TestCollectionProp;
+ procedure TestCollectionProp2;
+ procedure TestStrings;
+ procedure TestStrings2;
+ procedure TestStrings3;
+ end;
+
+implementation
+
+uses variants;
+
+{ TCJSONDeStreamer }
+
+procedure TCJSONDeStreamer.SetUp;
+begin
+ inherited SetUp;
+ FDS:=TJSONDeStreamer.Create(Nil)
+end;
+
+procedure TCJSONDeStreamer.TearDown;
+begin
+ FreeAndNil(FDS);
+ FreeAndNil(FJD);
+ FreeAndNil(FToFree);
+ inherited TearDown;
+end;
+
+procedure TCJSONDeStreamer.AssertVarType(Msg: String; AVarType: TVarType;
+ const Variant: Variant);
+begin
+ AssertEquals(Msg,VarTypeAsText(AVarType),VarTypeAsText(VarType(Variant)));
+end;
+
+procedure TCJSONDeStreamer.TestVariantInteger;
+
+Var
+ V : Variant;
+
+begin
+ JD:=TJSOnIntegerNumber.Create(12);
+ V:=DS.JSONToVariant(JD);
+ AssertVarType('Integer data',varInteger,V);
+ AssertEquals('Integer value',12,V);
+end;
+
+procedure TCJSONDeStreamer.TestVariantFloat;
+Var
+ V : Variant;
+
+begin
+ JD:=TJSOnFloatNumber.Create(1.2);
+ V:=DS.JSONToVariant(JD);
+ AssertVarType('Double data',varDouble,V);
+ AssertEquals('Float value',1.2,V);
+end;
+
+procedure TCJSONDeStreamer.TestVariantInt64;
+Var
+ V : Variant;
+
+begin
+ JD:=TJSONInt64Number.Create(123);
+ V:=DS.JSONToVariant(JD);
+ AssertVarType('Int64 data',varInt64,V);
+ AssertEquals('Int64 value',123,V);
+end;
+
+procedure TCJSONDeStreamer.TestVariantBoolean;
+Var
+ V : Variant;
+
+begin
+ JD:=TJSONBoolean.Create(True);
+ V:=DS.JSONToVariant(JD);
+ AssertVarType('Boolean data',varBoolean,V);
+ AssertEquals('Boolean value',True,V);
+end;
+
+procedure TCJSONDeStreamer.TestVariantNull;
+Var
+ V : Variant;
+
+begin
+ JD:=TJSONNull.Create();
+ V:=DS.JSONToVariant(JD);
+ AssertVarType('Null data',varNull,V);
+end;
+
+procedure TCJSONDeStreamer.TestVariantString;
+Var
+ V : Variant;
+
+begin
+ JD:=TJSONString.Create('A string');
+ V:=DS.JSONToVariant(JD);
+ AssertVarType('String data',varString,V);
+ AssertEquals('String data','A string',V);
+end;
+
+procedure TCJSONDeStreamer.TestVariantArray;
+Var
+ V : Variant;
+begin
+ JD:=TJSONArray.Create([1,2,3]);
+ V:=DS.JSONToVariant(JD);
+ AssertEQuals('Variant is array',true,VarIsArray(V));
+ AssertEquals('Lower bound is zero ',0,VarArrayLowBound(V,1));
+ AssertEquals('Higher bound is count-1 ',2,VarArrayHighBound(V,1));
+ AssertEquals('Element 0 value correct ',1,V[0]);
+ AssertEquals('Element 1 value correct ',2,V[1]);
+ AssertEquals('Element 2 value correct ',3,V[2]);
+end;
+
+procedure TCJSONDeStreamer.TestEmpty;
+begin
+ FTofree:=TComponent.Create(Nil);
+ DS.JSONToObject('{}',FTofree);
+ AssertEquals('Empty name','',TComponent(FToFree).Name);
+ AssertEquals('Empty Tag',0,TComponent(FToFree).Tag);
+end;
+
+procedure TCJSONDeStreamer.DeStream(JSON : TJSONStringType; AObject : TObject);
+
+begin
+ FToFree:=AObject;
+ DS.JSONToObject(JSON,FTofree);
+end;
+
+procedure TCJSONDeStreamer.DeStream(JSON: TJSONObject; AObject: TObject);
+begin
+ FToFree:=AObject;
+ JD:=JSON;
+ DS.JSONToObject(JSON,FTofree);
+end;
+
+procedure TCJSONDeStreamer.TestBoolean;
+
+Var
+ B : TBooleanComponent;
+
+begin
+ B:=TBooleanComponent.Create(Nil);
+ DeStream('{ "BooleanProp" : true }',B);
+ AssertEquals('Correct boolean value',true,B.BooleanProp);
+end;
+
+procedure TCJSONDeStreamer.TestInteger;
+
+Var
+ B : TIntegerComponent;
+
+begin
+ B:=TIntegerComponent.Create(Nil);
+ DeStream('{ "IntProp" : 22 }',B);
+ AssertEquals('Correct integer value',22,B.IntProp);
+end;
+
+procedure TCJSONDeStreamer.TestString;
+
+Var
+ B : TStringComponent;
+
+begin
+ B:=TStringComponent.Create(Nil);
+ DeStream('{ "StringProp" : "A nice string"}',B);
+ AssertEquals('Correct string value','A nice string',B.StringProp);
+end;
+
+procedure TCJSONDeStreamer.TestFloat;
+
+Var
+ B : TSingleComponent;
+
+begin
+ B:=TSingleComponent.Create(Nil);
+ DeStream('{ "SingleProp" : 2.34 }',B);
+ AssertEquals('Correct single value',2.34,B.SingleProp);
+end;
+
+procedure TCJSONDeStreamer.TestFloat2;
+
+Var
+ B : TDoubleComponent;
+
+begin
+ B:=TDoubleComponent.Create(Nil);
+ DeStream('{ "DoubleProp" : 3.45 }',B);
+ AssertEquals('Correct Double value',3.45,B.DoubleProp);
+end;
+
+procedure TCJSONDeStreamer.TestFloat3;
+Var
+ B : TExtendedComponent;
+
+begin
+ B:=TExtendedComponent.Create(Nil);
+ DeStream('{ "ExtendedProp" : 4.56 }',B);
+ AssertEquals('Correct extended value',4.56,B.ExtendedProp);
+end;
+
+procedure TCJSONDeStreamer.TestFloat4;
+
+Var
+ B : TCompComponent;
+
+begin
+ B:=TCompComponent.Create(Nil);
+ DeStream('{ "ExtendedProp" : 5.67 }',B);
+{$ifdef CPUX86_64}
+ AssertEquals('Correct comp value',round(5.67),B.ExtendedProp);
+{$else}
+ AssertEquals('Correct extended value',5.67,B.ExtendedProp);
+{$endif}
+end;
+
+procedure TCJSONDeStreamer.TestFloat5;
+Var
+ B : TCurrencyComponent;
+
+begin
+ B:=TCurrencyComponent.Create(Nil);
+ DeStream('{ "CurrencyProp" : 5.67 }',B);
+ AssertEquals('Correct string value',5.67,B.CurrencyProp);
+end;
+
+procedure TCJSONDeStreamer.TestEnum1;
+
+Var
+ E : TEnumcomponent;
+
+begin
+ E:=TEnumComponent.Create(Nil);
+ DeStream('{ "Dice" : 2 }',E);
+ AssertEquals('Correct value',2,Ord(E.Dice));
+end;
+
+procedure TCJSONDeStreamer.TestEnum2;
+
+Var
+ E : TEnumcomponent;
+
+begin
+ E:=TEnumComponent.Create(Nil);
+ DeStream('{ "Dice" : "three" }',E);
+ AssertEquals('Correct value',GetEnumName(TypeInfo(TDice),Ord(Three)),GetEnumName(TypeInfo(TDice),Ord(E.Dice)));
+end;
+
+procedure TCJSONDeStreamer.TestSet1;
+
+Var
+ T : TSetComponent;
+
+begin
+ T:=TSetComponent.Create(Nil);
+ DeStream('{ "Throw" : "one,two" }',T);
+ If not (T.Throw=[one,two]) then
+ Fail('Correct value for throw');
+end;
+
+procedure TCJSONDeStreamer.TestSet2;
+
+Var
+ T : TSetComponent;
+
+begin
+ T:=TSetComponent.Create(Nil);
+ DeStream('{ "Throw" : "[one,two]" }',T);
+ If not (T.Throw=[one,two]) then
+ Fail('Correct value for throw');
+end;
+
+procedure TCJSONDeStreamer.TestSet3;
+
+Var
+ T : TSetComponent;
+
+begin
+ T:=TSetComponent.Create(Nil);
+ DeStream('{ "Throw" : [ "one", "two"] }',T);
+ If not (T.Throw=[one,two]) then
+ Fail('Correct value for throw');
+end;
+
+procedure TCJSONDeStreamer.TestSet4;
+
+Var
+ T : TSetComponent;
+
+begin
+ T:=TSetComponent.Create(Nil);
+ DeStream('{ "Throw" : [ 0 , 1 ] }',T);
+ If not (T.Throw=[one,two]) then
+ Fail('Correct value for throw');
+end;
+
+procedure TCJSONDeStreamer.TestVariantProp;
+Var
+ V : TVariantComponent;
+
+begin
+ V:=TVariantComponent.Create(Nil);
+ DeStream('{ "VariantProp" : "A string" }',V);
+ AssertEquals('Variant property value','A string',V.VariantProp);
+end;
+
+procedure TCJSONDeStreamer.TestCollection;
+
+Var
+ C : TTestCollection;
+
+begin
+ C:=TTestCollection.Create;
+ DeStream('[ { "StrProp" : "one" }, { "StrProp" : "two" } ]',C);
+ AssertEquals('Item count',2,C.Count);
+ AssertEquals('Class item 0',TTestItem,C.Items[0].ClassType);
+ AssertEquals('Class item 1',TTestItem,C.Items[1].ClassType);
+ AssertEquals('Class item 0','one',TTestItem(C.Items[0]).StrProp);
+ AssertEquals('Class item 1','two',TTestItem(C.Items[1]).StrProp);
+end;
+
+procedure TCJSONDeStreamer.TestCollection2;
+
+Var
+ C : TTestCollection;
+
+begin
+ C:=TTestCollection.Create;
+ DeStream('{ "Items" : [ { "StrProp" : "one" }, { "StrProp" : "two" } ] }',C);
+ AssertEquals('Item count',2,C.Count);
+ AssertEquals('Class item 0',TTestItem,C.Items[0].ClassType);
+ AssertEquals('Class item 1',TTestItem,C.Items[1].ClassType);
+ AssertEquals('Class item 0','one',TTestItem(C.Items[0]).StrProp);
+ AssertEquals('Class item 1','two',TTestItem(C.Items[1]).StrProp);
+end;
+
+procedure TCJSONDeStreamer.TestCollection3;
+
+Var
+ C : TTestCollection;
+
+begin
+ C:=TTestCollection.Create;
+ FTofree:=C;
+ DS.JSONToCollection('{ "Items" : [ { "StrProp" : "one" }, { "StrProp" : "two" } ] }',C);
+ AssertEquals('Item count',2,C.Count);
+ AssertEquals('Class item 0',TTestItem,C.Items[0].ClassType);
+ AssertEquals('Class item 1',TTestItem,C.Items[1].ClassType);
+ AssertEquals('Class item 0','one',TTestItem(C.Items[0]).StrProp);
+ AssertEquals('Class item 1','two',TTestItem(C.Items[1]).StrProp);
+end;
+
+procedure TCJSONDeStreamer.TestCollection4;
+
+Var
+ C : TTestCollection;
+
+begin
+ C:=TTestCollection.Create;
+ FTofree:=C;
+ DS.JSONToCollection('[ { "StrProp" : "one" }, { "StrProp" : "two" } ]',C);
+ AssertEquals('Item count',2,C.Count);
+ AssertEquals('Class item 0',TTestItem,C.Items[0].ClassType);
+ AssertEquals('Class item 1',TTestItem,C.Items[1].ClassType);
+ AssertEquals('Class item 0','one',TTestItem(C.Items[0]).StrProp);
+ AssertEquals('Class item 1','two',TTestItem(C.Items[1]).StrProp);
+end;
+
+procedure TCJSONDeStreamer.TestCollection5;
+
+Var
+ C : TTestCollection;
+
+begin
+ C:=TTestCollection.Create;
+ FTofree:=C;
+ JD:=TJSONArray.Create([TJSONObject.Create(['StrProp','one']),TJSONObject.Create(['StrProp','two'])]);
+ DS.JSONToCollection(JD,C);
+ AssertEquals('Item count',2,C.Count);
+ AssertEquals('Class item 0',TTestItem,C.Items[0].ClassType);
+ AssertEquals('Class item 1',TTestItem,C.Items[1].ClassType);
+ AssertEquals('Class item 0','one',TTestItem(C.Items[0]).StrProp);
+ AssertEquals('Class item 1','two',TTestItem(C.Items[1]).StrProp);
+end;
+
+procedure TCJSONDeStreamer.TestCollection6;
+Var
+ C : TTestCollection;
+
+begin
+ C:=TTestCollection.Create;
+ FTofree:=C;
+ JD:=TJSONObject.Create(['Items',TJSONArray.Create([TJSONObject.Create(['StrProp','one']),TJSONObject.Create(['StrProp','two'])])]);
+ DS.JSONToCollection(JD,C);
+ AssertEquals('Item count',2,C.Count);
+ AssertEquals('Class item 0',TTestItem,C.Items[0].ClassType);
+ AssertEquals('Class item 1',TTestItem,C.Items[1].ClassType);
+ AssertEquals('Class item 0','one',TTestItem(C.Items[0]).StrProp);
+ AssertEquals('Class item 1','two',TTestItem(C.Items[1]).StrProp);
+end;
+
+procedure TCJSONDeStreamer.TestCollectionProp;
+
+Var
+ C : TCollection;
+
+begin
+ JD:=TJSONObject.Create(['Coll',TJSONArray.Create([TJSONObject.Create(['StrProp','one']),TJSONObject.Create(['StrProp','two'])])]);
+ DeStream(JD as TJSONObject,TCollectionComponent.Create(Nil));
+ C:=TCollectionComponent(ToFree).Coll;
+ AssertEquals('Item count',2,C.Count);
+ AssertEquals('Class item 0',TTestItem,C.Items[0].ClassType);
+ AssertEquals('Class item 1',TTestItem,C.Items[1].ClassType);
+ AssertEquals('Class item 0','one',TTestItem(C.Items[0]).StrProp);
+ AssertEquals('Class item 1','two',TTestItem(C.Items[1]).StrProp);
+end;
+
+procedure TCJSONDeStreamer.TestCollectionProp2;
+
+Var
+ C : TCollection;
+
+begin
+
+ DeStream('{ "Coll" : [ { "StrProp" : "one" }, { "StrProp" : "two" } ]}',TCollectionComponent.Create(Nil));
+ C:=TCollectionComponent(ToFree).Coll;
+ AssertEquals('Item count',2,C.Count);
+ AssertEquals('Class item 0',TTestItem,C.Items[0].ClassType);
+ AssertEquals('Class item 1',TTestItem,C.Items[1].ClassType);
+ AssertEquals('Class item 0','one',TTestItem(C.Items[0]).StrProp);
+ AssertEquals('Class item 1','two',TTestItem(C.Items[1]).StrProp);
+end;
+
+procedure TCJSONDeStreamer.TestStrings;
+
+Var
+ S : TStrings;
+
+begin
+ S:=TStringList.Create;
+ FTofree:=S;
+ DS.JSONToStrings('[ "one" , "two" ]',S);
+ AssertEquals('Item count',2,S.Count);
+ AssertEquals('First item','one',S[0]);
+ AssertEquals('First item','two',S[1]);
+end;
+
+procedure TCJSONDeStreamer.TestStrings2;
+
+Var
+ S : TStrings;
+
+begin
+ S:=TStringList.Create;
+ FTofree:=S;
+ DS.JSONToStrings('{ "Strings" : [ "one" , "two" ] }',S);
+ AssertEquals('Item count',2,S.Count);
+ AssertEquals('First item','one',S[0]);
+ AssertEquals('First item','two',S[1]);
+end;
+
+procedure TCJSONDeStreamer.TestStrings3;
+Var
+ S : TStrings;
+
+begin
+ S:=TStringList.Create;
+ FTofree:=S;
+ DS.JSONToStrings('{ "Strings" : [ "one" , "two" ] }',S);
+ AssertEquals('Item count',2,S.Count);
+ AssertEquals('First item','one',S[0]);
+ AssertEquals('First item','two',S[1]);
+end;
+
+{ TCJSONStreamer }
+
+function TCJSONStreamer.StreamObject(AObject: TObject): TJSONObject;
+begin
+ FToFree:=AObject;
+ FSR:=FRJ.ObjectToJSON(AObject);
+ Result:=FSR;
+end;
+
+procedure TCJSONStreamer.DoStreamProperty1(Sender: TObject; AObject: TObject;
+ Info: PPropInfo; var Res: TJSONData);
+begin
+ If (info^.name<>'IntProp') and (info^.name<>'Name') and (info^.name<>'Tag') then
+ Fail('Wrong property');
+ If (info^.name='IntProp') then
+ FreeAndNil(Res);
+ FCalled:=true;
+end;
+
+procedure TCJSONStreamer.SetUp;
+begin
+ Inherited;
+ FRJ:=TJSONStreamer.Create(Nil);
+end;
+
+procedure TCJSONStreamer.TearDown;
+begin
+ FreeAndNil(FSR);
+ FreeAndNil(FRJ);
+ FreeAndNil(FToFree);
+ Inherited;
+end;
+
+procedure TCJSONStreamer.AssertEquals(AMessage: String; Expected, Actual: TJSONType);
+begin
+ AssertEquals(AMessage,GetEnumName(TypeInfo(TJSONType),Ord(Expected)),
+ GetEnumName(TypeInfo(TJSONType),Ord(Actual)));
+end;
+
+procedure TCJSONStreamer.AssertPropCount(ACount: Integer);
+begin
+ AssertNotNull('Result of streaming available',FSR);
+ If FToFree is TComponent then
+ ACount:=ACount+2; // Tag + Name
+ Writeln(FSR.ASJSON);
+ AssertEquals('Property count correct',ACount,FSR.Count);
+end;
+
+function TCJSONStreamer.AssertProperty(APropName: String; AType: TJSONType
+ ): TJSONData;
+
+Var
+ i : Integer;
+
+begin
+ I:=FSR.IndexOfName(APropName);
+ If (I=-1) then
+ Fail('No property "'+APropName+'" available');
+ Result:=FSR.Items[i];
+ AssertEquals('Property "'+APropName+'" has correct type',GetEnumName(TypeInfo(TJSONType),Ord(AType)),
+ GetEnumName(TypeInfo(TJSONType),Ord(Result.JSONType)));
+end;
+
+procedure TCJSONStreamer.AssertProp(APropName: String; AValue: Boolean);
+begin
+ AssertNotNull('Result of streaming available',FSR);
+ AssertEquals('Result of streaming is TJSONObject',TJSONObject,FSR.ClassType);
+ AssertEquals('Correct value',AValue,AssertProperty(APropName,jtBoolean).AsBoolean);
+end;
+
+procedure TCJSONStreamer.AssertProp(APropName: String; AValue: Integer);
+begin
+ AssertNotNull('Result of streaming available',FSR);
+ AssertEquals('Result of streaming is TJSONObject',TJSONObject,FSR.ClassType);
+ AssertEquals('Correct value',AValue,AssertProperty(APropName,jtNumber).AsInteger);
+end;
+
+procedure TCJSONStreamer.AssertProp(APropName: String; AValue: String);
+begin
+ AssertNotNull('Result of streaming available',FSR);
+ AssertEquals('Result of streaming is TJSONObject',TJSONObject,FSR.ClassType);
+ AssertEquals('Correct value',AValue,AssertProperty(APropName,jtString).AsString);
+end;
+
+procedure TCJSONStreamer.AssertProp(APropName: String; AValue: TJSONFloat);
+begin
+ AssertNotNull('Result of streaming available',FSR);
+ AssertEquals('Result of streaming is TJSONObject',TJSONObject,FSR.ClassType);
+ AssertEquals('Correct value',AValue,AssertProperty(APropName,jtNumber).AsFloat);
+end;
+
+procedure TCJSONStreamer.AssertProp(APropName: String; AValue: array of String
+ );
+Var
+ a : TJSONArray;
+ i : integer;
+
+begin
+ a:=AssertArrayProp(APropName);
+ For I:=Low(AValue) to High(Avalue) do
+ begin
+ AssertEquals('Array element type',jtString,A.Types[i]);
+ AssertEquals('Array value',AValue[i],A.strings[i]);
+ end;
+end;
+
+procedure TCJSONStreamer.AssertProp(APropName: String; AValue: array of Integer
+ );
+Var
+ a : TJSONArray;
+ i : integer;
+
+begin
+ a:=AssertArrayProp(APropName);
+ For I:=Low(AValue) to High(Avalue) do
+ begin
+ AssertEquals('Array element type',jtNumber,A.Types[i]);
+ AssertEquals('Array value',AValue[i],A.Integers[i]);
+ end;
+end;
+
+function TCJSONStreamer.CreateVariantComp: TVariantComponent;
+begin
+ Result:=TVariantComponent.Create(Nil);
+ FTofree:=Result;
+end;
+
+procedure TCJSONStreamer.AssertNullProp(APropName: String);
+begin
+ AssertProperty(APropName,jtNull);
+end;
+
+function TCJSONStreamer.AssertObjectProp(APropName: String): TJSONObject;
+begin
+ Result:=AssertProperty(APropName,jtObject) as TJSONObject;
+end;
+
+function TCJSONStreamer.AssertArrayProp(APropName: String): TJSONArray;
+begin
+ Result:=AssertProperty(APropName,jtArray) as TJSONArray;
+end;
+
+procedure TCJSONStreamer.TestNil;
+begin
+ AssertNull('Nil returns nil',StreamObject(Nil));
+end;
+
+procedure TCJSONStreamer.TestEmpty;
+begin
+ StreamObject(TemptyPersistent.Create);
+ AssertPropCount(0);
+end;
+
+procedure TCJSONStreamer.TestEmptyComponent;
+begin
+ StreamObject(TComponent.Create(nil));
+ AssertPropCount(0);
+end;
+
+procedure TCJSONStreamer.TestWriteBoolean;
+
+begin
+ StreamObject(TBooleanComponent.Create(nil));
+ AssertPropCount(1);
+ AssertProp('BooleanProp',False);
+end;
+
+procedure TCJSONStreamer.TestWriteInteger;
+begin
+ StreamObject(TIntegerComponent.Create(Nil));
+ AssertPropCount(1);
+ AssertProp('IntProp',3);
+end;
+
+procedure TCJSONStreamer.TestWriteString;
+begin
+ StreamObject(TStringComponent.Create(Nil));
+ AssertPropCount(1);
+ AssertProp('StringProp','A string');
+end;
+
+procedure TCJSONStreamer.TestWriteFloat;
+begin
+ StreamObject(TSingleComponent.Create(Nil));
+ AssertPropCount(1);
+ AssertProp('SingleProp',1.23);
+end;
+
+procedure TCJSONStreamer.TestWriteFloat2;
+begin
+ StreamObject(TDoubleComponent.Create(Nil));
+ AssertPropCount(1);
+ AssertProp('DoubleProp',2.34);
+end;
+
+procedure TCJSONStreamer.TestWriteFloat3;
+begin
+ StreamObject(TExtendedComponent.Create(Nil));
+ AssertPropCount(1);
+ AssertProp('ExtendedProp',3.45);
+end;
+
+procedure TCJSONStreamer.TestWriteFloat4;
+begin
+ StreamObject(TCompComponent.Create(Nil));
+ AssertPropCount(1);
+ // Extended is correct, propname is wrong
+ {$ifdef CPUX86_64}
+ AssertProp('ExtendedProp',TJSONFloat(5));
+ {$else}
+ AssertProp('ExtendedProp',4.56);
+ {$endif}
+end;
+
+procedure TCJSONStreamer.TestWriteFloat5;
+begin
+ StreamObject(TCurrencyComponent.Create(Nil));
+ AssertPropCount(1);
+ AssertProp('CurrencyProp',5.67);
+end;
+
+procedure TCJSONStreamer.TestEnum1;
+begin
+ StreamObject(TEnumComponent3.Create(Nil));
+ AssertPropCount(1);
+ AssertProp('Dice',GetEnumName(TypeInfo(TDice),Ord(three)));
+end;
+
+procedure TCJSONStreamer.TestEnum2;
+begin
+ RJ.Options:=[jsoEnumeratedAsInteger];
+ StreamObject(TEnumComponent3.Create(Nil));
+ AssertProp('Dice',Ord(three));
+end;
+
+procedure TCJSONStreamer.TestSet1;
+begin
+ StreamObject(TSetComponent.Create(Nil));
+ AssertPropCount(1);
+ AssertProp('Throw',['two','five']);
+end;
+
+procedure TCJSONStreamer.TestSet2;
+begin
+ RJ.Options:=[jsoSetAsString];
+ StreamObject(TSetComponent.Create(Nil));
+ AssertPropCount(1);
+ AssertProp('Throw','two,five');
+end;
+
+procedure TCJSONStreamer.TestSet3;
+begin
+ RJ.Options:=[jsoSetAsString,jsoSetBrackets];
+ StreamObject(TSetComponent.Create(Nil));
+ AssertPropCount(1);
+ AssertProp('Throw','[two,five]');
+end;
+
+procedure TCJSONStreamer.TestSet4;
+begin
+ RJ.Options:=[jsoSetEnumeratedAsInteger];
+ StreamObject(TSetComponent.Create(Nil));
+ AssertPropCount(1);
+ AssertProp('Throw',[Ord(two),Ord(five)]);
+end;
+
+procedure TCJSONStreamer.TestObjectNil;
+
+Var
+ P : TOwnedComponent;
+
+begin
+ P:=TOwnedComponent.Create(Nil);
+ P.CompProp.Free;
+ P.CompProp:=Nil;
+ StreamObject(P);
+ AssertPropCount(1);
+ AssertNullProp('CompProp');
+end;
+
+procedure TCJSONStreamer.TestComponentProp1;
+begin
+ StreamObject(TOwnedComponent.Create(Nil));
+ AssertPropCount(1);
+ AssertProp('CompProp','SubComponent');
+end;
+
+procedure TCJSONStreamer.TestComponentProp2;
+
+Var
+ C : TOwnedComponent;
+ F : TJSONObject;
+
+begin
+ RJ.Options:=[jsoComponentsInline];
+ C:=TOwnedComponent.Create(Nil);
+ StreamObject(C);
+ AssertPropCount(1);
+ F:=SR;
+ try
+ SR:=AssertObjectProp('CompProp');
+ AssertPropCount(1);
+ AssertProp('Name','SubComponent');
+ Assertprop('Tag',0);
+ AssertProp('IntProp',3);
+ finally
+ SR:=F;
+ end;
+end;
+
+procedure TCJSONStreamer.TestCollectionProp1;
+
+Var
+ C : TCollectionComponent;
+ F : TJSONObject;
+ A : TJSONArray;
+
+begin
+ C:=TCollectionComponent2.Create(Nil);
+ StreamObject(C);
+ AssertPropCount(1);
+ F:=SR;
+ try
+ A:=AssertArrayProp('Coll');
+ AssertEquals('Collection item cound',3,A.Count);
+ AssertEquals('Item 0 is object',jtObject,A.Types[0]);
+ SR:=A.Objects[0];
+ FToFree:=SR;
+ AssertPropCount(1);
+ AssertProp('StrProp','First');
+ AssertEquals('Item 1 is object',jtObject,A.Types[1]);
+ SR:=A.Objects[1];
+ FToFree:=SR;
+ AssertPropCount(1);
+ AssertProp('StrProp','Second');
+ AssertEquals('Item 2 is object',jtObject,A.Types[2]);
+ SR:=A.Objects[2];
+ FToFree:=SR;
+ AssertPropCount(1);
+ AssertProp('StrProp','Third');
+ finally
+ SR:=F;
+ FToFree:=C;
+ end;
+end;
+
+procedure TCJSONStreamer.TestCollectionProp2;
+
+Var
+ C : TCollectionComponent;
+ F : TJSONObject;
+ A : TJSONArray;
+
+begin
+ C:=TCollectionComponent.Create(Nil);
+ StreamObject(C);
+ AssertPropCount (1);
+ A:=AssertArrayProp('Coll');
+ AssertEquals('Collection item count',0,A.Count);
+end;
+
+procedure TCJSONStreamer.TestPersistentProp1;
+
+var
+ P : TPersistentComponent;
+ F : TJSONObject;
+
+begin
+ P:=TPersistentComponent.Create(Nil);
+ StreamObject(P);
+ AssertPropCount(1);
+ F:=SR;
+ try
+ SR:=AssertObjectProp('Persist');
+ FToFree:=P.Persist;
+ AssertPropCount(2);
+ AssertProp('AString','A persistent string');
+ AssertProp('AInteger',3);
+ finally
+ FToFree:=P;
+ SR:=F;
+ end;
+end;
+
+procedure TCJSONStreamer.TestStringsProp1;
+
+Var
+ A : TJSONArray;
+begin
+ RJ.Options:=[jsoTstringsAsArray];
+ StreamObject(TStringsCOmponent.Create(Nil));
+ AssertPropCount(1);
+ AssertProp('StringsProp',['One','Two','Three']);
+end;
+
+procedure TCJSONStreamer.TestStringsProp2;
+
+Var
+ A : TJSONArray;
+begin
+ StreamObject(TStringsCOmponent.Create(Nil));
+ AssertPropCount(1);
+ AssertProp('StringsProp','One'+sLineBreak+'Two'+sLineBreak+'Three'+sLineBreak);
+end;
+
+procedure TCJSONStreamer.TestStringsProp3;
+
+Var
+ O : TJSONObject;
+ S : TStringsComponent;
+
+begin
+ S:=TStringsCOmponent.Create(Nil);
+ RJ.Options:=[jsoTstringsAsObject];
+ StreamObject(S);
+ AssertPropCount(1);
+ O:=SR;
+ SR:=AssertObjectprop('StringsProp');
+ FTofree:=Nil;
+ try
+ AssertNullProp('One');
+ AssertNullProp('Two');
+ AssertNullProp('Three');
+ finally
+ SR:=o;
+ FToFree:=S;
+ end;
+end;
+
+procedure TCJSONStreamer.TestStringsProp4;
+
+Var
+ O,SP : TJSONObject;
+ S : TStringsComponent;
+
+begin
+ S:=TStringsCOmponent.Create(Nil);
+ S.StringsProp.Objects[0]:=TEmptyPersistent.Create;
+ S.StringsProp.Objects[1]:=TEmptyPersistent.Create;
+ S.StringsProp.Objects[2]:=TEmptyPersistent.Create;
+ try
+ RJ.Options:=[jsoTstringsAsObject];
+ StreamObject(S);
+ AssertPropCount(1);
+ O:=SR;
+ SP:=AssertObjectprop('StringsProp');
+ SR:=SP;
+ FTofree:=Nil;
+ try
+ SR:=AssertObjectProp('One');
+ AssertPropCount(0);
+ SR:=SP;
+ SR:=AssertObjectProp('Two');
+ AssertPropCount(0);
+ SR:=SP;
+ SR:=AssertObjectProp('Three');
+ AssertPropCount(0);
+ finally
+ SR:=o;
+ FToFree:=S;
+ end;
+ finally
+ S.StringsProp.Objects[0].Free;
+ S.StringsProp.Objects[1].Free;
+ S.StringsProp.Objects[2].Free;
+ end;
+end;
+
+procedure TCJSONStreamer.TestStringsArray;
+
+Var
+ O : TJSONArray;
+ S : TStringList;
+
+begin
+ S:=TStringList.create;
+ try
+ S.Add('one');
+ O:=RJ.StreamTStringsArray(S);
+ try
+ AssertEquals('one element',1,O.Count);
+ AssertEquals('string type',jtString,O.Types[0]);
+ AssertEquals('string value','one',O.Strings[0]);
+ finally
+ FreeAndNil(O);
+ end;
+ finally
+ S.Free;
+ end;
+end;
+
+procedure TCJSONStreamer.TestStringsObject;
+
+Var
+ O : TJSONObject;
+ S : TStringList;
+
+begin
+ S:=TStringList.create;
+ try
+ S.AddObject('one',TEmptyPersistent.Create);
+ O:=RJ.StreamTStringsObject(S);
+ try
+ AssertEquals('one element',1,O.Count);
+ AssertEquals('Have property',0,O.IndexOfName('one'));
+ AssertEquals('string type',jtObject,O.Types['one']);
+ AssertEquals('string value','one',O.Names[0]);
+ finally
+ FreeAndNil(O);
+ end;
+ finally
+ S.Objects[0].FRee;
+ S.Free;
+ end;
+end;
+
+procedure TCJSONStreamer.TestStringsStream1;
+
+Var
+ D: TJSONData;
+ O : TJSONArray;
+ S : TStringList;
+
+begin
+ S:=TStringList.create;
+ try
+ S.Add('one');
+ RJ.Options:=[jsoTstringsAsArray];
+ D:=RJ.StreamTStrings(S);
+ try
+ AssertEquals('Correct type',jtArray,D.JSONType);
+ O:=D as TJSONArray;
+ AssertEquals('one element',1,O.Count);
+ AssertEquals('string type',jtString,O.Types[0]);
+ AssertEquals('string value','one',O.Strings[0]);
+ finally
+ FreeAndNil(O);
+ end;
+ finally
+ S.Free;
+ end;
+end;
+
+procedure TCJSONStreamer.TestStringsStream2;
+
+Var
+ D : TJSONData;
+ O : TJSONObject;
+ S : TStringList;
+
+begin
+ S:=TStringList.create;
+ try
+ S.AddObject('one',TEmptyPersistent.Create);
+ RJ.Options:=[jsoTstringsAsObject];
+ D:=RJ.StreamTstrings(S);
+ try
+ AssertEquals('Correct type',jtObject,D.JSONType);
+ O:=D as TJSONObject;
+ AssertEquals('one element',1,O.Count);
+ AssertEquals('Have property',0,O.IndexOfName('one'));
+ AssertEquals('string type',jtObject,O.Types['one']);
+ AssertEquals('string value','one',O.Names[0]);
+ finally
+ SR:=O;
+ end;
+ finally
+ S.Objects[0].FRee;
+ S.Free;
+ end;
+end;
+
+procedure TCJSONStreamer.TestStringsStream3;
+Var
+ O : TJSONObject;
+ S : TStringList;
+
+begin
+ S:=TStringList.create;
+ try
+ S.AddObject('one',TEmptyPersistent.Create);
+ RJ.Options:=[jsoTstringsAsObject];
+ SR:=RJ.ObjectToJSON(S);
+ O:=AssertObjectProp('Strings');
+ AssertEquals('one element',1,O.Count);
+ AssertEquals('Have property',0,O.IndexOfName('one'));
+ AssertEquals('string type',jtObject,O.Types['one']);
+ AssertEquals('string value','one',O.Names[0]);
+ finally
+ S.Objects[0].FRee;
+ S.Free;
+ end;
+end;
+
+procedure TCJSONStreamer.TestStringsStream4;
+Var
+ O : TJSONObject;
+ S : TStringList;
+
+begin
+ S:=TStringList.create;
+ try
+ S.AddObject('one',TEmptyPersistent.Create);
+ SR:=RJ.ObjectToJSON(S);
+ AssertProp('Strings','one'+sLinebreak);
+ finally
+ S.Objects[0].FRee;
+ S.Free;
+ end;
+end;
+
+procedure TCJSONStreamer.TestStringsStream5;
+Var
+ D : TJSONData;
+ S : TStringList;
+
+begin
+ S:=TStringList.create;
+ try
+ S.AddObject('one',TEmptyPersistent.Create);
+ D:=RJ.StreamTstrings(S);
+ try
+ AssertEquals('String data',jtString,D.JSONType);
+ AssertEquals('String value','one'+sLineBreak,D.AsString);
+ finally
+ D.free;
+ end;
+ finally
+ S.Objects[0].FRee;
+ S.Free;
+ end;
+end;
+
+procedure TCJSONStreamer.TestCollectionStream;
+
+Var
+ C : TTestCollection;
+ A : TJSONArray;
+
+begin
+ C:=TTestCollection.Create;
+ FToFree:=C;
+ TTestItem(C.Add).StrProp:='One';
+ TTestItem(C.Add).StrProp:='Two';
+ A:=RJ.StreamCollection(C);
+ try
+ AssertNotNull('Have result',A);
+ AssertEquals('2 items',2,A.Count);
+ AssertEquals('Type item 0,',jtObject,A.Types[0]);
+ AssertEquals('Type item 1,',jtObject,A.Types[1]);
+ SR:=A.Objects[0];
+ AssertPropCount(1);
+ AssertProp('StrProp','One');
+ SR:=A.Objects[1];
+ AssertPropCount(1);
+ AssertProp('StrProp','Two');
+ SR:=Nil;
+ finally
+ FreeAndNil(A);
+ end;
+end;
+
+procedure TCJSONStreamer.TestCollectionStream2;
+
+Var
+ C : TTestCollection;
+ A : TJSONArray;
+ o : TJSONObject;
+
+begin
+ C:=TTestCollection.Create;
+ TTestItem(C.Add).StrProp:='One';
+ TTestItem(C.Add).StrProp:='Two';
+ FToFree:=C;
+ StreamObject(C);
+ O:=SR;
+ try
+ A:=AssertProperty('Items',jtArray) as TJSONArray;
+ AssertNotNull('Have result',A);
+ AssertEquals('2 items',2,A.Count);
+ AssertEquals('Type item 0,',jtObject,A.Types[0]);
+ AssertEquals('Type item 1,',jtObject,A.Types[1]);
+ SR:=A.Objects[0];
+ AssertPropCount(1);
+ AssertProp('StrProp','One');
+ SR:=A.Objects[1];
+ AssertPropCount(1);
+ AssertProp('StrProp','Two');
+ SR:=Nil;
+ finally
+ SR:=O;
+ end;
+end;
+
+procedure TCJSONStreamer.TestOnStreamProperty;
+begin
+ RJ.OnStreamProperty:=@DoStreamProperty1;
+ StreamObject(TIntegerComponent.Create(Nil));
+ AssertPropCount(0);
+end;
+
+procedure TCJSONStreamer.TestDateTimeProp;
+
+Var
+ D : Double;
+begin
+ StreamObject(TDateTimeComponent.Create(Nil));
+ D:=EncodeDate(1996,8,1);
+ AssertPropCount(1);
+ AssertProp('DateTimeProp',D);
+end;
+
+procedure TCJSONStreamer.TestDateTimeProp2;
+Var
+ D : Double;
+begin
+ StreamObject(TDateTimeComponent2.Create(Nil));
+ D:=EncodeTime(23,20,0,0);
+ AssertPropCount(1);
+ AssertProp('DateTimeProp',D);
+end;
+
+procedure TCJSONStreamer.TestDateTimeProp3;
+Var
+ D : Double;
+begin
+ StreamObject(TDateTimeComponent3.Create(Nil));
+ D:=EncodeDate(1996,8,1)+EncodeTime(23,20,0,0);
+ AssertPropCount(1);
+ AssertProp('DateTimeProp',D);
+end;
+
+procedure TCJSONStreamer.TestDateTimeProp4;
+
+begin
+ RJ.Options:=[jsoDateTimeAsString];
+ StreamObject(TDateTimeComponent.Create(Nil));
+ AssertPropCount(1);
+ AssertProp('DateTimeProp',DateToStr(EncodeDate(1996,8,1)));
+end;
+
+procedure TCJSONStreamer.TestDateTimeProp5;
+
+begin
+ RJ.Options:=[jsoDateTimeAsString];
+ StreamObject(TDateTimeComponent2.Create(Nil));
+ AssertPropCount(1);
+ AssertProp('DateTimeProp',TimeToStr(EncodeTime(23,20,0,0)));
+end;
+
+procedure TCJSONStreamer.TestDateTimeProp6;
+
+begin
+ RJ.Options:=[jsoDateTimeAsString];
+ StreamObject(TDateTimeComponent3.Create(Nil));
+ AssertPropCount(1);
+ AssertProp('DateTimeProp',DateTimeToStr(EncodeDate(1996,8,1)+EncodeTime(23,20,0,0)));
+end;
+
+procedure TCJSONStreamer.TestDateTimeProp7;
+begin
+ RJ.Options:=[jsoDateTimeAsString];
+ RJ.DateTimeFormat:='hh:nn';
+ StreamObject(TDateTimeComponent3.Create(Nil));
+ AssertPropCount(1);
+ AssertProp('DateTimeProp',FormatDateTime('hh:nn',EncodeDate(1996,8,1)+EncodeTime(23,20,0,0)));
+end;
+
+procedure TCJSONStreamer.TestVariantShortint;
+
+Var
+ i : ShortInt;
+ C : TVariantComponent;
+
+begin
+ i:=3;
+ C:=CreateVariantComp;
+ C.VariantProp:=i;
+ AssertEquals('Variant type',VarTypeAsText(varshortint),VarTypeAsText(VarType(C.VariantProp)));
+ StreamObject(FTofree);
+ AssertPropCount(1);
+ AssertProp('VariantProp',3);
+end;
+
+procedure TCJSONStreamer.TestVariantbyte;
+Var
+ i : Byte;
+ C : TVariantComponent;
+
+begin
+ i:=3;
+ C:=CreateVariantComp;
+ C.VariantProp:=i;
+ AssertEquals('Variant type',VarTypeAsText(varByte),VarTypeAsText(VarType(C.VariantProp)));
+ StreamObject(FTofree);
+ AssertPropCount(1);
+ AssertProp('VariantProp',3);
+end;
+
+procedure TCJSONStreamer.TestVariantword;
+
+Var
+ i : Word;
+ C : TVariantComponent;
+
+begin
+ i:=3;
+ C:=CreateVariantComp;
+ C.VariantProp:=i;
+ AssertEquals('Variant type',VarTypeAsText(varWord),VarTypeAsText(VarType(C.VariantProp)));
+ StreamObject(FTofree);
+ AssertPropCount(1);
+ AssertProp('VariantProp',3);
+end;
+
+procedure TCJSONStreamer.TestVariantsmallint;
+
+Var
+ i : Smallint;
+ C : TVariantComponent;
+
+begin
+ i:=3;
+ C:=CreateVariantComp;
+ C.VariantProp:=i;
+ AssertEquals('Variant type',VarTypeAsText(varSmallint),VarTypeAsText(VarType(C.VariantProp)));
+ StreamObject(FTofree);
+ AssertPropCount(1);
+ AssertProp('VariantProp',3);
+end;
+
+procedure TCJSONStreamer.TestVariantinteger;
+Var
+ i : Integer;
+ C : TVariantComponent;
+
+begin
+ i:=3;
+ C:=CreateVariantComp;
+ C.VariantProp:=i;
+ AssertEquals('Variant type',VarTypeAsText(varInteger),VarTypeAsText(VarType(C.VariantProp)));
+ StreamObject(FTofree);
+ AssertPropCount(1);
+ AssertProp('VariantProp',3);
+end;
+
+procedure TCJSONStreamer.TestVariantlongword;
+
+Var
+ i : Cardinal;
+ C : TVariantComponent;
+
+begin
+ i:=3;
+ C:=CreateVariantComp;
+ C.VariantProp:=i;
+ AssertEquals('Variant type',VarTypeAsText(varLongword),VarTypeAsText(VarType(C.VariantProp)));
+ StreamObject(FTofree);
+ AssertPropCount(1);
+ AssertProp('VariantProp',3);
+end;
+
+procedure TCJSONStreamer.TestVariantint64;
+Var
+ i : Int64;
+ C : TVariantComponent;
+
+begin
+ i:=3;
+ C:=CreateVariantComp;
+ C.VariantProp:=i;
+ AssertEquals('Variant type',VarTypeAsText(varInt64),VarTypeAsText(VarType(C.VariantProp)));
+ StreamObject(FTofree);
+ AssertPropCount(1);
+ AssertProp('VariantProp',3);
+end;
+
+procedure TCJSONStreamer.TestVariantqword;
+Var
+ i : QWord;
+ C : TVariantComponent;
+
+begin
+ i:=3;
+ C:=CreateVariantComp;
+ C.VariantProp:=i;
+ AssertEquals('Variant type',VarTypeAsText(varQWord),VarTypeAsText(VarType(C.VariantProp)));
+ StreamObject(FTofree);
+ AssertPropCount(1);
+ AssertProp('VariantProp',3);
+end;
+
+procedure TCJSONStreamer.TestVariantsingle;
+Var
+ i : Single;
+ C : TVariantComponent;
+
+begin
+ i:=3.14;
+ C:=CreateVariantComp;
+ C.VariantProp:=VarAsType(3.14,varSingle);
+ AssertEquals('Variant type',VarTypeAsText(varSingle),VarTypeAsText(VarType(C.VariantProp)));
+ StreamObject(FTofree);
+ AssertPropCount(1);
+ AssertProp('VariantProp',3.14);
+end;
+
+procedure TCJSONStreamer.TestVariantdouble;
+
+Var
+ i : Double;
+ C : TVariantComponent;
+
+begin
+ i:=3.14;
+ C:=CreateVariantComp;
+ C.VariantProp:=i;
+ AssertEquals('Variant type',VarTypeAsText(varDouble),VarTypeAsText(VarType(C.VariantProp)));
+ StreamObject(FTofree);
+ AssertPropCount(1);
+ AssertProp('VariantProp',3.14);
+end;
+
+procedure TCJSONStreamer.TestVariantCurrency;
+Var
+ i : Currency;
+ C : TVariantComponent;
+
+begin
+ i:=3.14;
+ C:=CreateVariantComp;
+ C.VariantProp:=i;
+ AssertEquals('Variant type',VarTypeAsText(varCurrency),VarTypeAsText(VarType(C.VariantProp)));
+ StreamObject(FTofree);
+ AssertPropCount(1);
+ AssertProp('VariantProp',3.14);
+end;
+
+procedure TCJSONStreamer.TestVariantString;
+
+Var
+ i : String;
+ C : TVariantComponent;
+
+begin
+ i:='3.14';
+ C:=CreateVariantComp;
+ C.VariantProp:=i;
+ AssertEquals('Variant type',VarTypeAsText(varString),VarTypeAsText(VarType(C.VariantProp)));
+ StreamObject(FTofree);
+ AssertPropCount(1);
+ AssertProp('VariantProp','3.14');
+end;
+
+procedure TCJSONStreamer.TestVariantolestr;
+
+Var
+ i : String;
+ C : TVariantComponent;
+
+begin
+ i:='3.14';
+ C:=CreateVariantComp;
+ C.VariantProp:=VarAsType(i,varOleStr);
+ AssertEquals('Variant type',VarTypeAsText(varOleStr),VarTypeAsText(VarType(C.VariantProp)));
+ StreamObject(FTofree);
+ AssertPropCount(1);
+ AssertProp('VariantProp','3.14');
+end;
+
+procedure TCJSONStreamer.TestVariantboolean;
+Var
+ i : Boolean;
+ C : TVariantComponent;
+
+begin
+ i:=True;
+ C:=CreateVariantComp;
+ C.VariantProp:=i;
+ AssertEquals('Variant type',VarTypeAsText(varBoolean),VarTypeAsText(VarType(C.VariantProp)));
+ StreamObject(FTofree);
+ AssertPropCount(1);
+ AssertProp('VariantProp',True);
+end;
+
+procedure TCJSONStreamer.TestVariantDate;
+
+Var
+ i : TDateTime;
+ C : TVariantComponent;
+
+begin
+ i:=EncodeDate(2010,12,23);
+ C:=CreateVariantComp;
+ C.VariantProp:=i;
+ AssertEquals('Variant type',VarTypeAsText(varDate),VarTypeAsText(VarType(C.VariantProp)));
+ StreamObject(FTofree);
+ AssertPropCount(1);
+ AssertProp('VariantProp',EncodeDate(2010,12,23));
+end;
+
+procedure TCJSONStreamer.TestVariantDate2;
+
+Var
+ i : TDateTime;
+ C : TVariantComponent;
+
+begin
+ RJ.Options:=[jsoDateTimeAsString];
+ i:=EncodeDate(2010,12,23);
+ C:=CreateVariantComp;
+ C.VariantProp:=i;
+ AssertEquals('Variant type',VarTypeAsText(varDate),VarTypeAsText(VarType(C.VariantProp)));
+ StreamObject(FTofree);
+ AssertPropCount(1);
+ AssertProp('VariantProp',DateToStr(EncodeDate(2010,12,23)));
+end;
+
+procedure TCJSONStreamer.TestVariantArray;
+Var
+ i : Integer;
+ V : Variant;
+ C : TVariantComponent;
+ A : TJSONArray;
+
+begin
+ V:=VarArrayCreate([1,10],varInteger);
+ For I:=1 to 10 do
+ V[i]:=11-I;
+ C:=CreateVariantComp;
+ C.VariantProp:=V;
+ StreamObject(FTofree);
+ AssertPropCount(1);
+ A:=AssertProperty('VariantProp',jtArray) as TJSONArray;
+ AssertEquals('10 elements in array',10,A.Count);
+ For I:=1 to 10 do
+ begin
+ assertEquals('Type of element',jtNumber,A.Types[i-1]);
+ AssertEquals('Value of element',11-i,A.Integers[i-1]);
+ end;
+end;
+
+procedure TCJSONStreamer.TestMultipleProps;
+begin
+ StreamObject(TMultipleComponent.Create(Nil));
+ AssertPropCount(5);
+ AssertProp('IntProp',1);
+ Assertprop('StringProp','A String');
+ AssertProp('CurrencyProp',2.3);
+ AssertProp('Throw',['three','four']);
+ AssertProp('Dice','two');
+end;
+
+procedure TCJSONStreamer.TestObjectToJSONString;
+begin
+ StreamObject(TIntegerComponent.Create(Nil));
+ AssertEquals('Correct stream',SR.AsJSON,RJ.ObjectToJSONString(FToFree));
+end;
+
+procedure TCJSONStreamer.TestStringsToJSONString;
+Var
+ S : TStrings;
+begin
+ S:=TStringList.Create;
+ try
+ S.Add('one');
+ S.Add('two');
+ S.Add('three');
+ AssertEquals('StringsToJSONString','["one", "two", "three"]',RJ.StringsToJSON(S));
+ AssertEquals('StringsToJSONString','{ "one" : null, "two" : null, "three" : null }',RJ.StringsToJSON(S,True));
+ finally
+ FreeAndNil(S);
+ end;
+end;
+
+procedure TCJSONStreamer.TestCollectionToJSONString;
+
+Var
+ C : TTestCollection;
+
+begin
+ C:=TTestCollection.Create;
+ try
+ (C.Add as TTestItem).StrProp:='one';
+ (C.Add as TTestItem).StrProp:='two';
+ (C.Add as TTestItem).StrProp:='three';
+ AssertEquals('CollectionToJSON','[{ "StrProp" : "one" }, { "StrProp" : "two" }, { "StrProp" : "three" }]',RJ.CollectionToJSON(C));
+ finally
+ FreeAndNil(C);
+ end;
+end;
+
+procedure TCJSONStreamer.TestChildren;
+
+Var
+ C : TChildrenComponent;
+
+begin
+ C:=TChildrenComponent.Create(Nil);
+ TComponent.Create(C).Name:='Child1';
+ TComponent.Create(C).Name:='Child2';
+ StreamObject(C);
+ If SR.IndexOfName('Children')<>-1 then
+ Fail('Children streamed with default options');
+
+end;
+
+procedure TCJSONStreamer.TestChildren2;
+Var
+ C : TChildrenComponent;
+ A : TJSONArray;
+ O : TJSONObject;
+
+begin
+ C:=TChildrenComponent.Create(Nil);
+ TComponent.Create(C).Name:='Child1';
+ TComponent.Create(C).Name:='Child2';
+ RJ.Options:=[jsoStreamChildren];
+ StreamObject(C);
+ AssertPropCount(1);
+ A:=AssertProperty('Children',jtArray) as TJSONArray;
+ O:=SR;
+ try
+ AssertEquals('2 Elements in array',2,A.Count);
+ AssertEquals('First in array is object',jtObject,A.Types[0]);
+ AssertEquals('Second in array is object',jtObject,A.Types[1]);
+ SR:=A.Objects[0];
+ AssertProp('Name','Child1');
+ SR:=A.Objects[1];
+ AssertProp('Name','Child2');
+ finally
+ SR:=O;
+ end;
+end;
+
+initialization
+
+ RegisterTests([TCJSONStreamer,TCJSONDeStreamer]);
+end.
+