Anonymous avatar Anonymous committed eedf10b

Some bugfixes to TASComponentProvider.
Cleaned up Demo app a bit.

Comments (0)

Files changed (4)

Demo/TestMain.dfm

   Left = 0
   Top = 0
   Caption = 'AS Provider Demo App'
-  ClientHeight = 593
-  ClientWidth = 967
+  ClientHeight = 268
+  ClientWidth = 720
   Color = clBtnFace
   Font.Charset = DEFAULT_CHARSET
   Font.Color = clWindowText
     Top = 146
     Width = 65
     Height = 17
-    DataField = 'Name'
+    DataField = 'Caption'
     DataSource = DataSource1
   end
   object Button1: TButton
   object DBGrid1: TDBGrid
     Left = 0
     Top = 0
-    Width = 967
+    Width = 720
     Height = 137
     Align = alTop
     DataSource = DataSource1
     DataSource = DataSource1
     TabOrder = 3
   end
-  object DBGrid2: TDBGrid
-    Left = 0
-    Top = 376
-    Width = 967
-    Height = 217
-    Align = alBottom
-    Anchors = [akLeft, akTop, akRight, akBottom]
-    DataSource = DataSource2
-    TabOrder = 4
-    TitleFont.Charset = DEFAULT_CHARSET
-    TitleFont.Color = clWindowText
-    TitleFont.Height = -11
-    TitleFont.Name = 'Tahoma'
-    TitleFont.Style = []
-  end
-  object DBNavigator2: TDBNavigator
-    Left = 8
-    Top = 345
-    Width = 240
-    Height = 25
-    DataSource = DataSource2
-    TabOrder = 5
-  end
   object DBEdit1: TDBEdit
     Left = 569
     Top = 143
     Height = 21
     DataField = 'Caption'
     DataSource = DataSource1
-    TabOrder = 6
+    TabOrder = 4
     OnChange = DBEdit1Change
   end
   object Button3: TButton
     Width = 75
     Height = 25
     Action = Action4
-    TabOrder = 7
+    TabOrder = 5
   end
   object Button4: TButton
     Left = 254
     Width = 75
     Height = 25
     Action = Action1
-    TabOrder = 8
+    TabOrder = 6
   end
   object ASComponentProvider1: TASComponentProvider
     Active = True
-    FieldDefs = <
-      item
-        Name = 'Name'
-        DataType = ftWideString
-        Size = 20
-      end
-      item
-        Name = 'Caption'
-        DataType = ftWideString
-        Size = 20
-      end
-      item
-        Name = 'Left'
-        DataType = ftInteger
-      end
-      item
-        Name = 'Top'
-        DataType = ftInteger
-      end
-      item
-        Name = 'Width'
-        DataType = ftInteger
-      end
-      item
-        Name = 'Height'
-        DataType = ftInteger
-      end>
+    DeclaredOnly = True
     ProvidedComponent = Button1
-    Left = 56
-    Top = 176
+    Left = 48
+    Top = 208
   end
   object ClientDataSet1: TClientDataSet
     Active = True
     Aggregates = <>
     Params = <>
     ProviderName = 'ASComponentProvider1'
-    Left = 56
-    Top = 224
-    object ClientDataSet1Name: TWideStringField
-      FieldName = 'Name'
-    end
+    Left = 168
+    Top = 208
     object ClientDataSet1Caption: TWideStringField
       FieldName = 'Caption'
     end
-    object ClientDataSet1Left: TIntegerField
-      FieldName = 'Left'
+    object ClientDataSet1Enabled: TBooleanField
+      FieldName = 'Enabled'
     end
-    object ClientDataSet1Top: TIntegerField
-      FieldName = 'Top'
+    object ClientDataSet1Visible: TBooleanField
+      FieldName = 'Visible'
     end
   end
   object DataSource1: TDataSource
+    AutoEdit = False
     DataSet = ClientDataSet1
-    Left = 160
-    Top = 176
-  end
-  object DataSource2: TDataSource
-    DataSet = DS
-    OnDataChange = DataSource2DataChange
-    OnUpdateData = DataSource2UpdateData
-    Left = 136
-    Top = 280
+    Left = 272
+    Top = 208
   end
   object ActionList1: TActionList
-    Left = 56
-    Top = 280
+    Left = 368
+    Top = 208
     object Action1: TAction
       Caption = 'Open'
       OnExecute = Action1Execute
       OnUpdate = Action4Update
     end
   end
-  object DS: TClientDataSet
-    Aggregates = <>
-    FieldDefs = <
-      item
-        Name = 'TMySet'
-        ChildDefs = <
-          item
-            Name = 'TMySetFieldKey'
-            DataType = ftString
-            Size = 20
-          end
-          item
-            Name = 'TMySetFieldValue'
-            DataType = ftString
-            Size = 20
-          end>
-        DataType = ftArray
-        Size = 10
-      end>
-    IndexDefs = <>
-    Params = <>
-    StoreDefs = True
-    Left = 248
-    Top = 280
-  end
 end

Demo/TestMain.pas

     ASComponentProvider1: TASComponentProvider;
     ClientDataSet1: TClientDataSet;
     DataSource1: TDataSource;
-    ClientDataSet1Name: TWideStringField;
-    ClientDataSet1Caption: TWideStringField;
-    ClientDataSet1Left: TIntegerField;
-    ClientDataSet1Top: TIntegerField;
-    DataSource2: TDataSource;
-    DBGrid2: TDBGrid;
-    DBNavigator2: TDBNavigator;
     DBText1: TDBText;
     DBEdit1: TDBEdit;
     Button3: TButton;
     Button4: TButton;
     Action3: TAction;
     Action4: TAction;
-    DS: TClientDataSet;
+    ClientDataSet1Caption: TWideStringField;
+    ClientDataSet1Enabled: TBooleanField;
+    ClientDataSet1Visible: TBooleanField;
     procedure Button1Click(Sender: TObject);
     procedure Button2Click(Sender: TObject);
-    procedure DataSource2DataChange(Sender: TObject; Field: TField);
-    procedure DataSource2UpdateData(Sender: TObject);
     procedure DBEdit1Change(Sender: TObject);
     procedure Button3Click(Sender: TObject);
     procedure Action1Update(Sender: TObject);
   ClientDataSet1.CancelUpdates;
 end;
 
-procedure TMainForm.DataSource2DataChange(Sender: TObject; Field: TField);
-begin
-  OutputDebugString('## DATA CHANGE');
-end;
-
-procedure TMainForm.DataSource2UpdateData(Sender: TObject);
-begin
-  OutputDebugString('## UPDATE DATA');
-end;
-
 procedure TMainForm.DBEdit1Change(Sender: TObject);
 begin
   with (Sender as TDBEdit) do

Src/ASProvider.pas

     FStreamedActive: Boolean;
     FDataSet: TPacketDataSet;
     FDSWriter: TDataPacketWriter;
-    FFieldDefs: TFieldDefs;
 
   private
     function GetDataSet: TPacketDataSet;
     function GetDSWriter: TDataPacketWriter;
     function GetFieldDefs: TFieldDefs;
-    procedure SetFieldDefs(const Value: TFieldDefs);
     procedure SetActive(const Value: Boolean);
+    function GetFieldDefList: TFieldDefList;
 
   protected
     function CreateResolver: TCustomResolver; override;
     procedure InitializeDataset; virtual;
     property DataSet: TPacketDataSet read GetDataSet;
     property DSWriter: TDataPacketWriter read GetDSWriter;
+    property FieldDefs: TFieldDefs read GetFieldDefs;
 
   public
     constructor Create(AOwner: TComponent); override;
     procedure Refresh;
 
     property Active: Boolean read FActive write SetActive;
-    property FieldDefs: TFieldDefs read GetFieldDefs write SetFieldDefs;
     property Options default [poDisableInserts, poDisableDeletes, poUseQuoteChar];
+    property FieldDefList: TFieldDefList read GetFieldDefList;
   end;
 
   TASObjectProvider = class(TASCustomProvider)
   private
     FClass: TClass;
     FObject: TObject;
+    FDeclaredOnly: Boolean;
+    procedure SetDeclaredOnly(const Value: Boolean);
 
   protected
     procedure CheckAncestor(const Value, Ancestor: TClass); virtual;
     procedure SetProvidedObject(const Value: TObject); virtual;
     function GetProvidedObject: TObject; virtual;
 
+    function GetPropertyValue(Prop: TRttiProperty; Obj: TObject): Variant;
     procedure ExtractObjectData(Obj: TObject); virtual;
 
     procedure ExtractMetaData; override;
     procedure ApplyDelete(Index: Integer); override;
 
   public
+    property DeclaredOnly: Boolean read FDeclaredOnly write SetDeclaredOnly;
     property ProvidedClass: TClass read GetProvidedClass write SetProvidedClass;
     property ProvidedObject: TObject read GetProvidedObject write SetProvidedObject;
   end;
   TASProvider = class(TASObjectProvider)
   published
     property Active;
-    property FieldDefs;
+    property DeclaredOnly;
     property Options;
   end;
 
 
   published
     property Active;
-    property FieldDefs;
+    property DeclaredOnly;
     property ProvidedComponent: TComponent read GetProvidedComponent write SetProvidedComponent;
     property Options;
   end;
 
   TASStringArrayProvider = class(TASCustomArrayProvider<string>)
   published
+    property Active;
     property ArrayName;
-    property Active;
-    property FieldDefs;
     property Options;
   end;
 
 constructor TASCustomProvider.Create(AOwner: TComponent);
 begin
   inherited Create(AOwner);
-  FFieldDefs := DefaultFieldDefsClass.Create(DataSet);
   Options := [poDisableInserts, poDisableDeletes, poUseQuoteChar];
 end;
 
 destructor TASCustomProvider.Destroy;
 begin
   FreeAndNil(FDSWriter);
-  FreeAndNil(FFieldDefs);
   FreeAndNil(FDataSet);
 
   inherited;
   Result := FDSWriter;
 end;
 
+function TASCustomProvider.GetFieldDefList: TFieldDefList;
+begin
+  Result := DataSet.FieldDefList;
+end;
+
 function TASCustomProvider.GetFieldDefs: TFieldDefs;
 begin
-  Result := FFieldDefs;
+  if DataSet.Active then
+    DataSet.Close;
+
+  Result := DataSet.FieldDefs;
 end;
 
 procedure TASCustomProvider.InitializeDataset;
 begin
-  DataSet.Active := False;
-  DataSet.FieldDefs := FieldDefs;
+  if DataSet.Active then
+    DataSet.Close;
+
   DataSet.CreateDataSet;
 end;
 
     FStreamedActive := Value
   else if Active <> Value then begin
     if Value then begin
-      if FieldDefs.Count = 0 then
-        ExtractMetaData;
+      ExtractMetaData;
       ExtractData;
       DataSet.First;
     end;
   end;
 end;
 
-procedure TASCustomProvider.SetFieldDefs(const Value: TFieldDefs);
-begin
-  FFieldDefs.Assign(Value);
-end;
-
 { TASResolver }
 
 procedure TASResolver.DoDelete(Tree: TUpdateTree);
 
 procedure TASObjectProvider.ApplyDelete(Index: Integer);
 begin
-
+  inherited;
 end;
 
 procedure TASObjectProvider.ApplyInsert(var Index: Integer);
 begin
-
+  inherited;
 end;
 
 procedure TASObjectProvider.ApplyUpdate(Index: Integer; const FieldName: string; const Value: Variant);
   try
     T := Ctx.GetType(Target.ClassType);
     P := T.GetProperty(FieldName);
-    if Assigned(P) and (P.GetValue(Target).AsVariant <> Value) then begin
+    if Assigned(P) and (GetPropertyValue(P, Target) <> Value) then begin
       P.SetValue(Target, TValue.FromVariant(Value));
     end;
   finally
 
 procedure TASObjectProvider.CheckProvidedObject(const Value: TObject);
 begin
-  CheckAncestor(Value.ClassType, ProvidedClass);
+  if Assigned(Value) then
+    CheckAncestor(Value.ClassType, ProvidedClass);
 end;
 
 procedure TASObjectProvider.ExtractData;
   P: TRttiProperty;
   F: TFieldType;
 
+  function Properties: TArray<TRttiProperty>;
+  begin
+    if DeclaredOnly then
+      Exit(T.GetDeclaredProperties);
+
+    Result := T.GetProperties;
+  end;
+
 begin
   FieldDefs.Clear;
 
     T := Ctx.GetType(ProvidedClass);
     FieldDefs.BeginUpdate;
     try
-      for P in T.GetProperties do begin
+      for P in Properties do begin
         if not ((P.Visibility in [mvPublic, mvPublished]) and P.IsReadable) then
           Continue;
 
           if R then
             F.ReadOnly := False;
 
-          F.Value := P.GetValue(Obj).AsVariant;
-
+          F.Value := GetPropertyValue(P, Obj);
           if R then
             F.ReadOnly := True;
         end;
   Result := FObject;
 end;
 
+function TASObjectProvider.GetPropertyValue(Prop: TRttiProperty; Obj: TObject): Variant;
+var
+  V: TValue;
+  I: Integer;
+begin
+  Result := varEmpty;
+  V := Prop.GetValue(Obj);
+  if not V.TryAsType<Variant>(Result) then
+    if V.DataSize <= SizeOf(I) then begin
+      I := 0;
+      V.ExtractRawData(@I);
+      Result := I;
+    end;
+end;
+
+procedure TASObjectProvider.SetDeclaredOnly(const Value: Boolean);
+begin
+  if FDeclaredOnly = Value then Exit;
+  FDeclaredOnly := Value;
+  ExtractMetaData;
+end;
+
 procedure TASObjectProvider.SetProvidedClass(const Value: TClass);
 begin
+  if FClass = Value then Exit;
   FClass := Value;
 
-  if not (FieldDefs.Count > 0) or (csReading in ComponentState) then
+  if Active then
     ExtractMetaData;
 end;
 

Test/TestASProvider.pas

     property Aint: Integer read Fint write Fint;
   end;
 
+  TTestDeclaredData = class(TTestData)
+  private
+    FAnotherProp: string;
+  public
+    property AnotherProp: string read FAnotherProp write FAnotherProp;
+  end;
+
   TTestGenericProvider = class(TASGenericProvider<TTestData>)
   published
     property Active;
-    property FieldDefs;
     property ProvidedTypedObject;
   end;
 
   strict private
     FProvider: TASCustomProvider;
   protected
-    procedure CheckFieldDef(FieldDefs: TFieldDefs; Expect: TExpectFieldDef; const Msg: string = '');
+    procedure CheckFieldDef(FieldDefs: TFieldDefList; Expect: TExpectFieldDef; const Msg: string = '');
     procedure CheckMetaData(ExpectFields: array of TExpectFieldDef; const Msg: string = '');
     procedure CheckItem(Expect: TExpectItem; const Msg: string = '');
     procedure CheckCollection(ExpectItems: array of TExpectItem; const Msg: string = '');
   protected
     function Provider: T;
     function GetProviderClass: TASCustomProviderClass; override;
+
+    {skipped tests}
+    procedure TestModifiedFieldDefs;
+    procedure TestStreamingDFM;
+
   published
     procedure TestProvidedClass;
     procedure TestMetaData;
+    procedure TestDeclaredMetaData_AllFields;
+    procedure TestDeclaredOnlyMetaData;
     procedure TestData;
-    procedure TestModifiedFieldDefs;
-    procedure TestStreamingDFM;
     procedure TestApply;
   end;
 
-  TestCollectionProvider = class(TTestASProviderTestCase)
+  // Test methods for class TASCollectionProvider
+
+  TestTASCollectionProvider = class(TTestASProviderTestCase)
   protected
     function Provider: TASCollectionProvider;
     function GetProviderClass: TASCustomProviderClass; override;
     procedure TestInsertUpdateDeleteData;
   end;
 
+  TestTASComponentProvider = class(TTestASProviderTestCase)
+  protected
+    function Provider: TASComponentProvider;
+    function GetProviderClass: TASCustomProviderClass; override;
+
+  published
+    procedure TestProvidedClass;
+    procedure TestMetaData;
+    procedure TestData;
+  end;
+
   // Test methods for class TASResolver
 
   TestTASResolver = class(TTestCase)
     (Idx: 2; Name: 'Aint';      Size: 0;  DataType: ftInteger;    Attr: [])
   );
 
+  TestDeclaredMetaDataAll_fields: array[0..3] of TExpectFieldDef = (
+    (Idx: 0; Name: 'AnotherProp'; Size: 20; DataType: ftWideString;     Attr: []),
+    (Idx: 1; Name: 'Astring';     Size: 20; DataType: ftWideString; Attr: []),
+    (Idx: 2; Name: 'AroString';   Size: 20; DataType: ftWideString; Attr: [faReadonly]),
+    (Idx: 3; Name: 'Aint';        Size: 0;  DataType: ftInteger;    Attr: [])
+  );
+
+  TestDeclaredMetaDataDeclaredOnly_fields: array[0..0] of TExpectFieldDef = (
+    (Idx: 0; Name: 'AnotherProp'; Size: 20; DataType: ftWideString;     Attr: [])
+  );
+
   TestModified_fields: array[0..1] of TExpectFieldDef = (
     (Idx: 0; Name: 'Astring';         Size: 35; DataType: ftString;   Attr: []),
     (Idx: 1; Name: 'MyModifiedInt';   Size: 0;  DataType: ftInteger;  Attr: [])
     (Idx: 4; Name: 'DisplayName'; Size: 20; DataType: ftWideString; Attr: [])
   );
 
+  TestTButtonMetaData_fields: array[0..2] of TExpectFieldDef = (
+    (Idx: 0; Name: 'Astring';   Size: 20; DataType: ftWideString; Attr: []),
+    (Idx: 1; Name: 'AroString'; Size: 20; DataType: ftWideString; Attr: [faReadonly]),
+    (Idx: 2; Name: 'Aint';      Size: 0;  DataType: ftInteger;    Attr: [])
+  );
+
   TestCollectionItems_PreCondition: array[0..2] of TExpectItem = (
     (Idx: 0; Astring: 'My first string'; Aint: 123),
     (Idx: 1; Astring: 'My second string'; Aint: 456),
 implementation
 
 uses
-  Forms, Rtti, StrUtils;
+  Forms, Rtti, StrUtils, StdCtrls;
 
 function TestTASProviders<T>.GetProviderClass: TASCustomProviderClass;
 begin
   end;
 end;
 
+procedure TestTASProviders<T>.TestDeclaredMetaData_AllFields;
+begin
+  Provider.ProvidedClass := TTestDeclaredData;
+  CheckEquals(TTestDeclaredData, Provider.ProvidedClass, 'Provided class');
+  CheckMetaData(TestDeclaredMetaDataAll_fields);
+end;
+
+procedure TestTASProviders<T>.TestDeclaredOnlyMetaData;
+begin
+  Provider.DeclaredOnly := True;
+  Provider.ProvidedClass := TTestDeclaredData;
+  CheckEquals(TTestDeclaredData, Provider.ProvidedClass, 'Provided class');
+  CheckMetaData(TestDeclaredMetaDataDeclaredOnly_fields);
+end;
+
 procedure TestTASProviders<T>.TestMetaData;
 begin
   Provider.ProvidedClass := TTestData;
 
 procedure TestTASProviders<T>.TestModifiedFieldDefs;
 begin
+  {skipped}
+
   Provider.ProvidedClass := TTestData;
   CheckMetaData(TestMetaData_fields, 'Original');
 
     ExpectedException := EArgumentException;
 
   Provider.ProvidedClass := Self.ClassType;
-  Check(Provider.ProvidedClass = Self.ClassType);
+  CheckEquals(Self.ClassType, Provider.ProvidedClass, 'Provided class');
 end;
 
 procedure TestTASProviders<T>.TestStreamingDFM;
 var
   Stream: TMemoryStream;
 begin
+  {skipped}
+
   Provider.ProvidedClass := TTestData;
   with Provider.FieldDefs do begin
     Find('AroString').Free;
   end;
 end;
 
-{ TestCollectionProvider }
+{ TestTASCollectionProvider }
 
-function TestCollectionProvider.GetProviderClass: TASCustomProviderClass;
+function TestTASCollectionProvider.GetProviderClass: TASCustomProviderClass;
 begin
   Result := TASCollectionProvider;
 end;
 
-function TestCollectionProvider.Provider: TASCollectionProvider;
+function TestTASCollectionProvider.Provider: TASCollectionProvider;
 begin
   Result := CustomProvider as TASCollectionProvider;
 end;
 
-procedure TestCollectionProvider.TestData;
+procedure TestTASCollectionProvider.TestData;
 var
   C: TCollection;
   DS: TClientDataSet;
   end;
 end;
 
-procedure TestCollectionProvider.TestDeleteData;
+procedure TestTASCollectionProvider.TestDeleteData;
 var
   C: TCollection;
   DS: TClientDataSet;
   end;
 end;
 
-procedure TestCollectionProvider.TestInsertData;
+procedure TestTASCollectionProvider.TestInsertData;
 var
   C: TCollection;
   DS: TClientDataSet;
       1: "My third string" #789
       2: "My new string" #321
 }
-procedure TestCollectionProvider.TestInsertUpdateDeleteData;
+procedure TestTASCollectionProvider.TestInsertUpdateDeleteData;
 var
   C: TCollection;
   DS: TClientDataSet;
   end;
 end;
 
-procedure TestCollectionProvider.TestMetaData;
+procedure TestTASCollectionProvider.TestMetaData;
 var
   C: TCollection;
 begin
   end;
 end;
 
-procedure TestCollectionProvider.TestProvidedClass;
+procedure TestTASCollectionProvider.TestProvidedClass;
 var
   C: TCollection;
 begin
   C := TCollection.Create(TTestItem);
   try
     Provider.ProvidedCollection := C;
-    Check(Provider.ProvidedClass = TTestItem, 'Provided class');
+    CheckEquals(TTestItem, Provider.ProvidedClass, 'Provided class');
   finally
     C.Free;
   end;
     CheckItem(ExpectItems[I], Msg);
 end;
 
-procedure TTestASProviderTestCase.CheckFieldDef(FieldDefs: TFieldDefs; Expect: TExpectFieldDef; const Msg: string);
+procedure TTestASProviderTestCase.CheckFieldDef(FieldDefs: TFieldDefList; Expect: TExpectFieldDef; const Msg: string);
 var
   S: string;
 begin
   I: Integer;
   S: string;
 begin
+  CustomProvider.Open;
+
   if Length(Msg) > 0 then
     S := Msg + ', '
   else
     S := '';
 
   try
-    CheckEquals(ExpectFields[High(ExpectFields)].Idx + 1, CustomProvider.FieldDefs.Count, S + 'Unexpected number of field defs');
+    CheckEquals(ExpectFields[High(ExpectFields)].Idx + 1, CustomProvider.FieldDefList.Count, S + 'Unexpected number of field defs');
   except
     with TStringBuilder.Create do try
       Append('Actual fields:').AppendLine;
-      for I := 0 to CustomProvider.FieldDefs.Count - 1 do
-        AppendFormat('%d: %s', [I, CustomProvider.FieldDefs[I].Name]).AppendLine;
+      for I := 0 to CustomProvider.FieldDefList.Count - 1 do
+        AppendFormat('%d: %s', [I, CustomProvider.FieldDefList[I].Name]).AppendLine;
 
       Status(ToString);
     finally
   end;
 
   for I := Low(ExpectFields) to High(ExpectFields) do
-    CheckFieldDef(CustomProvider.FieldDefs, ExpectFields[I], Msg);
+    CheckFieldDef(CustomProvider.FieldDefList, ExpectFields[I], Msg);
 end;
 
 function TTestASProviderTestCase.GetProviderClass: TASCustomProviderClass;
   FreeAndNil(FProvider);
 end;
 
+{ TestTASComponentProvider }
+
+function TestTASComponentProvider.GetProviderClass: TASCustomProviderClass;
+begin
+  Result := TASComponentProvider;
+end;
+
+function TestTASComponentProvider.Provider: TASComponentProvider;
+begin
+  Result := TASComponentProvider(CustomProvider);
+end;
+
+procedure TestTASComponentProvider.TestData;
+var
+  B: TButton;
+  DS: TClientDataSet;
+begin
+  CheckFalse(IsConsole, 'This test requires a GUI form to run');
+  B := TButton.Create(nil);
+  DS := TClientDataSet.Create(Application);
+  try
+    B.Parent := Screen.FocusedForm;
+    B.Name := 'MyButton';
+    B.Caption := 'Click me';
+
+    Provider.ProvidedComponent := B;
+    CheckEquals(TButton, Provider.ProvidedClass, 'Provided class');
+    Provider.Name := 'TestProvider';
+
+    DS.ProviderName := 'TestProvider';
+    DS.Open;
+
+    CheckEquals(1, DS.RecordCount, 'Record count');
+    CheckEqualsString('MyButton', DS.FieldByName('Name').AsString);
+    CheckEqualsString('Click me', DS.FieldByName('Caption').AsString);
+
+  finally
+    B.Free;
+    DS.Free;
+  end;
+end;
+
+procedure TestTASComponentProvider.TestMetaData;
+begin
+  Provider.ProvidedClass := TButton;
+  Provider.Open;
+
+  CheckEquals(68, Provider.FieldDefList.Count, 'All Fields');
+
+  Provider.DeclaredOnly := True;
+  CheckEquals(30, Provider.FieldDefList.Count, 'Declared Only Fields');
+
+//  CheckMetaData(TestTButtonMetaData_fields);
+end;
+
+procedure TestTASComponentProvider.TestProvidedClass;
+begin
+  Provider.ProvidedClass := TButton;
+  CheckEquals(TButton, Provider.ProvidedClass, 'Provided class');
+end;
+
 initialization
   // Register any test cases with the test runner
   RegisterTest('Provider', TestTASProviders<TASProvider>.Suite);
   RegisterTest('Provider', TestTASProviders<TTestGenericProvider>.Suite);
-  RegisterTest('Provider', TestCollectionProvider.Suite);
+  RegisterTest('Provider', TestTASCollectionProvider.Suite);
+  RegisterTest('Provider', TestTASComponentProvider.Suite);
   RegisterTest('Resolver', TestTASResolver.Suite);
 end.
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.