FailNotEquals expects AnsiString as 2nd parameter - freepascal

I am writing a test case using fpc unit in lazarus, doing some investigation on how TDateTime behaves.
Now the question is why the counterpart of AssignEquals, which I presume is FailNotEquals can't accept the parameters to be Word, Word as AssignEquals can.
Here is my code:
procedure TTestCase1.Test3;
var d1, d2: TDateTime;
var hour1, minute1, second1, ms1: Word;
var hour2, minute2, second2, ms2: Word;
begin
d2:=Now;
Sleep(10);
d1:=Now;
DecodeTime(d1, hour1, minute1, second1, ms1);
DecodeTime(d2, hour2, minute2, second2, ms2);
//AssertEquals(ms1, ms2); // This test fails as expected
FailNotEquals(ms1, ms2); // Cant compile, param 2 must be AnsiString
AssertEquals(d1, d2); // How can this slip through...
end;
test

FailNotEquals is defined in DUnitCompatibleInterface.inc as:
class procedure FailNotEquals(expected, actual: string;
msg: string = ''; errorAddr: Pointer = nil); virtual;
The method is not overloaded, so only the string parameters are accepted.

Related

Freepascal procedure parameter of file type default value

A class method has a simple definition
PROCEDURE Print (str : string = ''; VAR f : text);
This gives the compiler error
Error: (3185) Default parameter required for "F"
This is strange because on this page it says "default values are not supported for variable parameters." Ignoring that, adding a default value:
PROCEDURE Print (str : string = ''; VAR f : text = stderr);
gives the compiler error
Error: (3203) Illegal expression
What is the correct syntax here (by correct I mean how can I make the compiler happy)?
Once a parameter have a default value all the parameters that follow must also have a default, this is why you have
Error: (3185) Default parameter required for "F"
At this point of the compilation, FPC didn't detect that, grammatically speaking, F couldn't have a default parameter, it just see that there is no default.
You declaration should rather be
PROCEDURE Print (VAR f : text; str : string = '');
To go further, let's take this function:
procedure foo(a: integer = 8; b: integer);
If you call it like this
foo(4);
The compiler wouldn't know if 4 is for a and you forget b or if 4 is for b. That's why default parameters must always be put at the end. That's also why FPC would emit the following error:
Error: Default parameter required for "B"
Additional to #Nestedtype explanation.
It can be solved using overloaded methods without changes in parameter order like
PROCEDURE Print (str : string; VAR f : text); overload; // Calls as Print('foo', f);
PROCEDURE Print (VAR f : text); overload; // Calls as Print(f);
and in the implementation section:
PROCEDURE Print (str : string; VAR f : text);
begin
// Do what you need
end;
PROCEDURE Print (VAR f : text);
begin
Print('', f); // Here '' is the "default" value
end;

Warnings in local functions of anonymous functions

What is the cause of (apparently) spurious warnings when compiling local functions of anonymous functions, and how do I eliminate them.
A simple function compiles clean - no warnings. If the function is a local function of another function, again there are no warnings. If the function is a local function of an anonymous function it gives rise to the following warnings:
[DCC Warning] Unit1.pas(57): W1036 Variable 'i' might not have been initialized
[DCC Warning] Unit1.pas(58): W1035 Return value of function 'StrToJType' might be undefined
Example code is set out below. Please note that though this code compiles, it gives warnings unrelated to this question because it is incomplete.
EDIT
Comments and responses suggest that the fact that the example code contains no return value in the anonymous function may be the cause of the problem. This edit amends the code to remedy this, to simplify the local function case, and to minimise the code. The problem is still the same.
unit Unit1;
interface
type
JType = (JAtLeastOnce, JConditionLine, JInfix, JIteration, JNonNullInfix );
TFuncTest = reference to function : JType;
function StrToJType(aString : string) : JType;
implementation
function StrToJType(aString : string) : JType;
// Basic function - does not give warnings
var
i : integer;
begin
i := Pos(aString, '+i*-?');
if i <> 0 then result := JType(i - 1) else result := High(JType);
end;
function Test : JType;
// Local function - does not give warnings
function StrToJType(aString : string) : JType;
var
i : integer;
begin
i := Pos(aString, '+i*-?');
if i <> 0 then result := JType(i - 1) else result := High(JType);
end;
begin
result := low(JType);
end;
function Test2 : TFuncTest;
// Local function of anonymous function - gives warnings
begin
result :=
function : JType
function StrToJType(aString : string) : JType;
var
i : integer;
begin
i := Pos(aString, '+i*-?');
if i <> 0 then result := JType(i - 1) else result := High(JType);
end;
begin
result := Low(JType);
end;
end;
end.
Your anonymous function does not assign its return value.
function Test2 : TFuncTest;
// Local function of anonymous function - gives warnings
begin
result :=
function : JStructureType
function StrToJType(aString : string) : JStructureType;
const
c : string = '+i*-?p!qoxsc<^>8|';
var
i : integer;
begin
i := Pos(aString, c);
if (aString <> '') and (i <> 0) then result := JStructureType(i - 1)
else result := High(JStructureType);
end;
begin
// need to return something here
end;
end;
The compiler should also object to you making the same mistake in Test.
If the compiler really is complaining about StrToJType after you've fixed all the other errors, that would be a compiler bug and should be submitted to Quality Portal.
Update
Your edit confirms that the warnings in the local function remain when you resolve the other mistakes. So this would appear to be a compiler bug. Please make a minimal reproduction and submit it.
Of course Delphi XE won't be updated in the future. Unless this bug still exists in XE8 there's probably no point in reporting a bug.
One might suspect that the compiler is confused by a local function, local to an anonymous method, that is never called

How to compare string to integer with while do loop in pascal?

How to compare string to integer using while loop in Pascal?
Like this:
var Destination:string;
while (Destination>'11') do begin
writeln('Error');
write('Destination Number');
readln(Destination);
end;
You have to convert Destination to an integer:
program Project1;
uses sysutils;
var
converted: integer;
Destination: string;
begin
converted := 12;
Destination := '';
while (converted > 11) do
begin
writeln('Error');
writeln('Destination Number');
readln(Destination);
converted := StrToIntDef(Destination, 12);
end;
end.
convertion routines are avalaible in sysutils:
http://www.freepascal.org/docs-html/rtl/sysutils/index-5.html
Why not just do the conversion in the WHILE--DO statement?
ReadLn(Destination);
WHILE StrToInt(Destination) > 11 DO NumberIsTooHigh;
where NumberIsTooHigh simply is a procedure you write to handle your "error". Ex:
PROCEDURE NumberIsTooHigh;
BEGIN
WriteLn('Your number is above valid range');
write('Destination Number');
readln(Destination);
END;
The reason for the previous routine to make "error" on the first run is that "Destination" does not yet have a value at all. The converted-variable is then set manually to 12, just outside the Ok-range, hence it will always produce the error on startup.

TJson.JsonToObject<T> throws errors in a multi-thread environment

When using TJson.JsonToObject in a multi-thread environment random access violations occur. I was searching a long time for the problem and I could isolate it with the following code
JSON class
type
TParameter = class
public
FName : string;
FDataType : string;
FValue : string;
end;
Testfunction:
procedure Test();
var
myTasks: array of ITask;
i : integer;
max : integer;
begin
max := 50;
SetLength(myTasks, max);
for i := 0 to max -1 do begin
myTasks[i] := TTask.Create(procedure ()
var
json : string;
p : TParameter;
begin
json := '{"name":"NameOfParam","dataType":"TypeOfParam","value":"ValueOfParam"}';
p := TJson.JsonToObject<TParameter>(json);
p.Free;
end);
myTasks[i].Start;
end;
TTask.WaitForAll(myTasks);
ShowMessage('all done!');
end;
It's only a code snippet based of a much more complex source. As long I use this code in a single thread everything works without a problem. I'm wondering if there is anything wrong with the code.
The method TJSONUnMarshal.ObjectInstance in REST.JsonReflect.pas has a severe bug:
It calls FreeAndNil on a TRttiType instance. This should never be done because all TRtti*** instances are managed by the TRttiContext.
After I removed the FreeAndNil call I could not reproduce the access violation anymore.
Reported as: https://quality.embarcadero.com/browse/RSP-10035
P.S. I also think that https://quality.embarcadero.com/browse/RSP-9815 will affect your code.

Encoding a message with Vigenere cipher in Delphi?

I want to encrypt a message with a simple Vigenere cipher by assigning each letter in the alphabet a numeric value e.g. A= 1; B= 2;..Z= 26. The problem is I don't know which function to use to recognize a character in a string(as it is a message that has to be encoded, complete with spaces), and then giving it a specific, numeric value.
Next up, that numeric message has to be converted into binary, which is easy, but how do I convert that message that was a string into an integer(other that the StrToInt function)?
I just need to know which function to use for the Vigenere Cipher.
*I am still in High school so I apologize in advance for using the wrong terms.
You can use a case statement to perform the encoding.
function EncodedChar(C: Char): Byte;
begin
case C of
'A'..'Z':
Result := 1 + ord(C) - ord('A');
' ':
Result := ???;
',':
Result := ???;
... // more cases here
else
raise ECannotEncodeThisCharacter.Create(...);
end;
end;
Encode a string with a for loop:
function EncodedString(const S: string): TBytes;
var
i: Integer;
begin
SetLength(Result, Length(S));
for i := 1 to Length(S) do begin
// dynamic arrays are 0-based, strings are 1-based, go figure!
Result[i-1] := EncodedChar(S[i]);
end;
end;