Using Delphi how can I check if a field of an object is a TList ?
I tryed using this
var
c : TRttiContext;
t : TRttiType;
f : TRttiField;
begin
c := TRttiContext.Create;
t := c.GetType(Self.ClassType);
for f in t.GetFields do begin
//check if the field is TList<T>
//check also the Generic type T
end;
end;
You have to use the IsType<T> method if you want to check for TList (the one from System.Classes).
If you want to check if it is a TList<T> you have to do some string parsing of the class name. Even more so if you want to check the specific type of T. This is because Delphi has no special RTTI about generic types and it does not support open generic types.
You can look at the Spring.Helpers unit from Spring4D how this can be solved.
Some example code using this:
if f.FieldType.IsGenericType then
if f.FieldType.GetGenericTypeDefinition = 'TList<>' then
if f.FieldType.GetGenericArguments[0].Handle = TypeInfo(TMyClass) then
Writeln('found');
You can check if object contains ToArray() method:
var
method: TRttiMethod;
begin
...
method := f.FieldType.GetMethod('ToArray');
if Assigned(method) then
begin
//...
end;
Note, however, that this will return True for all TList<> descendants too.
Related
I want to write junit for this method returning country List
public List<String> getCountries(String countryCd) {
String sql = "select COUNTRY_NAME from MY_COUNTRY WHERE COUNTRY_CD = :countryCd ";
List<String> countries;
SqlParameterSource parameters = new MapSqlParameterSource().addValue("countryCd", countryCd);
countries = namedParameterJdbcTemplate.query(sql,parameters, (resultSet, rowNum) ->
resultSet.getString("COUNTRY_NAME")));
return countries
}
I tried something like this
Mockito.when(namedParameterJdbcTemplate.queryForObject(queryJobs, parameters, String.class))
MapSqlParameterSource inherits its equals method from Object.
This means that 2 parameter sources are equal only if they reference same instance.
You need to provide an argument matcher to compare this argument and not use equals method. The cleanest way to do it is via Custom Argument Matcher.
Alternatively, you relax the requirements for this argument and use any(MapSqlParameterSource.class) matcher.
try using
Mockito.when(namedParameterJdbcTemplate.queryForObject(any(), any(), any())).thenRetrun(you v
grails 3.3.9, + tag libs
I create a new taglib like this
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
class JavaDateTimeTagLib {
static defaultEncodeAs = [taglib:'html']
//static encodeAsForTags = [tagName: [taglib:'html'], otherTagName: [taglib:'none']]
static encodeAsForTags = [testCall: [taglib:'none']]
static namespace = "jdt" //java8 date time name space for tags
def testCall = { attrs ->
def p1 = attrs.p1
def p2 = attrs.p2
out << "p1:'$p1' with class ${p1.getClass()}"
out << "p2:'$p2' with class ${p2.getClass()}"
}
}
where i want to pass a non string variable to the attrs map.
i then setup the test like this
class JavaDateTimeTagLibSpec extends Specification implements TagLibUnitTest<JavaDateTimeTagLib> {
def setup() {
}
def cleanup() {
}
/**
* restriction params must be quoted values - esentially strings
* taglib has to take that and do any conversions in the taglib
* output by defaults is encoded html using std codec
*/
void "call displayDateTime tag "() {
given:
String result = applyTemplate('<jdt:testCall p1="p1-string" p2="$now" />' , [now:LocalDateTime.now()])
when :
println "$result "
then:
result
}
}
What i'm trying to do is pass a LocalDateTime variable to the attrs map.
if you use applyTemplate and pass p2=ldt, and test map [ldt:LocalDateTime.now()]
the test fails saying the variable must be 'quoted
[Byte array resource [test_1549319950845]:1] Attribute value must be quoted (p1="p1-string" p2=now).
if you quote the p2 variable using p2="$ldt" and test map the sname as [ldt:LocalDateTime.now()], then the test will work - However the type passed to the attrs map is GStringImpl
however reading the OCI guide oci tag lib guide
it implies on page 4 that you can pass attrs.employees as a list of domainobjects and use that in you markup
but theres no way to invoke this using the testing as everything has to be string quoted - which makes it GStringImpl
how do you pass non string variable to a taglibs attrs map from appyTemplate (.. i presume the same restiction applies in live gsp and not just the testing framework )
hah! its such a small thing
if you change the test and write this
String result = applyTemplate('<jdt:testCall p1="p1-string" p2="${now}" />' , [now:LocalDateTime.now()])
with braces round the variable key name from the map - then the actual value of the typed variable is passed into the taglib. so if you look in the attrs.p2 value it has the actual LocalDateTime instance.
now quite sure how applytemplate is working not sure, but expecting its trying to do soemthing like groovy shell evaluate the string - hence the need to use single '' like '
Hope that makes sense
blimey enough to make your head explode sometimes
How to provide data for Unit Tests in Delphi DUnit) ? For example, in PHP, you can do something like this:
public function URLProvider() {
return [
["https://helloacm.com"],
["https://codingforspeed.com"]
];
}
/**
* #dataProvider URLProvider
*/
public function test_url($url) {
$data = file_get_contents("$this->API?url=$url");
$result = json_decode($data, true);
$this->assertEquals(true, $result['result']);
$this->assertEquals(200, $result['code']);
}
With Spring4D DUnit extensions you can write something like that (look into the release/1.2 branch in the Tests\Source folder for the unit Spring.Testing).
program Tests;
uses
Spring.Testing,
TestInsight.DUnit;
type
TUrlTests = class(TTestCase)
public
class function UrlProvider: TArray<string>; static;
published
[TestCaseSource('UrlProvider')]
procedure TestUrl(const url: string);
end;
{ TUrlTests }
procedure TUrlTests.TestUrl(const url: string);
begin
// do whatever
end;
class function TUrlTests.UrlProvider: TArray<string>;
begin
Result := ['https://helloacm.com', 'https://codingforspeed.com'];
end;
begin
TUrlTests.Register;
RunRegisteredTests;
end.
You can either pass the name to the method within the same Testcase class or specify another class - the method itself must be a public static class function. The extension then will create different test cases for each parameter being passed. You can check the Unittests of Spring4D for other use cases.
In DUnit every single test case has to be a procedure without parameters. So there can't exist a mechanism for injecting arguments via custom attributes to test methods like you are doing it PHPUnit.
You should take a look at DUnitX instead where you can define tests like this:
[TestCase('https://helloacm.com')]
[TestCase('https://codingforspeed.com']
procedure TestUrl(const Url: String);
Considering an attribute which take a delegate ( predicate function as std.algorithm.filter )
struct Section( alias pred ){}
This is used to annotate a field like this:
struct A {
#Section!( ( words ) => words[0] == '#' )
string b;
int c;
}
Field b is annotate by a delegate which return true if a string start by # when called
So how to retrieve all field which are annotated by #Section ?
Is it possible to called at runtime his delegate with a string as parameter and know if is true or not ?
thanks
So how to retrieve all field which are annotated by #Section ?
First, use allMembers or .tupleof to enumerate over all the fields of the struct.
Then, enumerate over all attributes attached to each field using getAttributes. Check if #Section is present in the field.
Is it possible to called at runtime his delegate with a string as parameter and know if is true or not ?
You should save an alias within the Section structure. For example:
struct Section(alias pred)
{
alias fun = pred;
}
Then, just reference the getAttributes result tuple member.
Hi I have one question regarding some type casting approaches. I am translating some Delphi files to C++. I have delphi declaration of class which is derived from TList and it's a base class for other derived classes.
type TBaseItem = class (TObject)
public
procedure SomeProcedure; virtual; abstract;
end;
Type TBaseClass = class(TList)
private
function GetItem(Index: Integer): TBaseItem;
procedure SetItem(Value: TBaseItem; Index: Integer);
public
property Items[Index: Integer]: TBaseItem read GetItem write SetItem;
end;
function TBaseClass.GetItem(Index: Integer): TBaseItem;
begin
Result := TBaseItem(inherited Items[Index]);
end;
procedure TBaseClass.SetItem(Value: TBaseItem; Index: Integer);
begin
inherited Items[Index] := Value;
end;
This are two base classe TBaseItem and TBaseClass. So here are declared new classes TchildItem which is derived from TBaseItem and TChildClass which is derived from TBaseClass. TChildItem is overriding method SomeMethod and what is more important is that TChildtClass is overriding property Items in a way that now we are returning TParentItem items insted of TBaseItem.
type TChildItem = class (TBaseItem)
public
procedure SomeProcedure; override;
end;
type TChildClass = class(TBaseClass)
private
function GetItem(Index: Integer): TChildItem;
procedure SetItem(Value: TChildItem; Index: Integer);
public
property Items[Index: Integer]: TChildItemread GetItem write SetItem;
end;
function TChildClass .GetItem(Index: Integer): TChildItem;
begin
Result := TChildItem(inherited Items[Index]);
end;
procedure TChildClass.SetItem(Value: TChildItem; Index: Integer);
begin
inherited Items[Index] := Value;
end;
With this example I wanted to show how easy can be done deriving classes and overriding properties. Getting proper type of item out of a list is simply done by calling parents (base) property Item and typecast it to proper type. This is delphi apporach.
I wonder how can I translate this part of code to C++. Currently I declared a new base class which is not derived from any class and it has public var Items which is
class TBaseItem{
virtual void SomeMethod();
}
class TBaseClass {
public:
vector<TBaseItem> Items;
};
class TChildItem : public TBaseItem{
}
class TChildClass : public TBaseClass {
};
and then use
return (TChildItem) Items[Idx]
That means I would like to access parent's (TBaseClass) public variables such as that vector Items and typecast it to proper type... My first impression is that I might be going into wrong direction with that Delphi approach.
What do you suggest? How should I go with that?
THANK YOU VERY MUCH!
The Delphi code is old and pre-dates generics, the Delphi analogue to C++ templates. In modern Delphi code those list classes would simply not exist. Instead one would use TList<TBaseItem> and TList<TChildItem>.
In C++ code you would simply use vector<TBaseItem*> and vector<TChildItem*>. There is simply no point in your C++ translation to implement TBaseClass and TChildClass.
I would also correct your terminology. Delphi properties cannot be overriden. The new property in TChildClass is just that, a new property.