3

My question is similar to this one, but instead of a set, I'd like to pass an array of integers.

Per example:

[TestCase('TestAdd','[1,2,3,4];[1,2,3,4]',';')]
procedure TestAdd(aValue, aResult: array of integer);

Modifying the DUnitX.Utils seems like the cleanest approach, but I'm not sure how to go about doing the conversion. My main question is, how will it know that I need specifically an array of integers? Is there something in the PTypeInfo that I can take advantage of?

Community
  • 1
  • 1
ColinM
  • 33
  • 3

1 Answers1

6

You cannot use an open array because the RTTI is missing code to invoke methods with such arguments (which are implemented by actually two arguments under the hood). So you need to change the signature to use TArray<T> or any other dynamic array type.

Then the modification to DUnitX.Utils is really easy - just add this function to the Conversions array for tkUString->tkDynArray (any possible optimization is left as an exercise for the reader):

function ConvStr2DynArray(const ASource: TValue; ATarget: PTypeInfo; out AResult: TValue): Boolean;
var
  s: string;
  values: TStringDynArray;
  i: Integer;
  p: Pointer;
  v1, v2: TValue;
  elType: PTypeInfo;
begin
  s := ASource.AsString;
  if StartsStr('[', s) and EndsStr(']', s) then
    s := Copy(s, 2, Length(s) - 2);
  values := SplitString(s, ',');
  i := Length(values);
  p := nil;
  DynArraySetLength(p, ATarget, 1, @i);
  TValue.MakeWithoutCopy(@p, ATarget, AResult);
  elType := ATarget.TypeData.DynArrElType^;
  for i := 0 to High(values) do
  begin
    v1 := TValue.FromString(values[i]);
    if not v1.TryConvert(elType, v2) then
      Exit(False);
    AResult.SetArrayElement(i, v2);
  end;
  Result := True;
end;
Stefan Glienke
  • 20,860
  • 2
  • 48
  • 102
  • I added your provided function (and added it to the conversion matrix) and changed my test to use TArray, but the arrays are both uninitialized resulting in AVs in my test. Is there something else I'm missing? – ColinM Feb 22 '16 at 16:02
  • Make sure that your project uses your DUnitX modifications (and not the units that are shipped with Seattle). – Stefan Glienke Feb 22 '16 at 16:31
  • I modified the installed one in Program Files. Do I need to do anything special to force it to rebuild or something? – ColinM Feb 22 '16 at 16:35
  • Of course - you need to add the DUnitX sources dir to your project search path to cause the compiler to build those units. Otherwise it just uses the shipped dcus of DUnitX located in the $(BDSLib) directory. – Stefan Glienke Feb 22 '16 at 16:51
  • It seems the environment variable Delphi automatically set up for $(DUNITX) was in my search path, but was invalid, and thus did not work. I put in the full path and now it works. Thanks a lot. – ColinM Feb 22 '16 at 16:55