Checking textual representation of a class in a test? - smalltalk

Lets say I've created a class MyClass in Pharo Smalltalk...
If I in Workspace write:
MyClass new.
and select print-it (Ctrl-P), I get:
A MyClass
With a bit of tinkering with MyClass's printOn: method,
I could get a bit more, for example:
A MyClass with value: 5
+++
So comes my question... How can I make a test (instance of TestCase-class)
that checks that the textual-representation of MyObject - what I would get
if I did "MyObject new" and Print-It - is what it's supposed to be?
How do I get the textual representation so I can check it against a
string-constant with what it should be, when I do a self assert: equal: (or something similar) in my test?
For example that after using my cutomized printOn: method, it will
look something like
A MyClass with value: 5
Sorry for such a newbie question, but there goes...

To get the textual representation of an object you can send the message printString to the object. For example Object new printString will return you the string 'an Object'.
To create a test case you should create a subclass of TestCase:
TestCase subclass: #MyClassTestCase
instanceVariableNames: ''
classVariableNames: ''
package: 'MyTest-Package'
Then a test is a method that begins with test. For example the following test verifies the string representation of Object new:
testClassRepresentation
self assert: Object new printString equals: 'an Object'

Related

Pharo initialize an object with an OrderedCollection

Indeed it is within the framework of a research. I'm trying to generate random values ​​for the instance variables of an X object. So when instantiating the object, I replace the parameters of the object initialization method with the values ​​that are generated.
So, I manage to retrieve instance variables, generate random values. The problem now is how to replace the arguments of the initialization method with the generated values?
we have my Person class
Object subclass: #Person
instanceVariableNames: 'name lastName birthDate'
classVariableNames: ''
package: 'Moi'
the method that i use to initialize a person is:
withName: aName andBirthDate: aBirthDate andLastName: aLastName
name:= aName.
lastName:= aLastName.
birthDate:= aBirthDate
For example I have the method
Person>>#withName:aName andBirthDate:aBirthDate andLastName:aLasatName
and I have the following values:
"toto", "13 sept 2022" and "tata"
How to override or rebuild method like this
Person>>#withName:'toto' andBirthDate:'13 Sep 2022'andLastName:'tata'?
```bri
the Person class is an example. Instead of the Person class, we can have Point, Car or any other class.
No, you will need to call the constructor and break out the arguments:
Person
withName: (list at: 1)
lastName: (list at: 2)
birthDay: (list at: 3)

Object argument to mock EXPECT_CALL

I have a simple mock class:
class MockCanInterface : public lib::CanInterface {
public:
MockCanInterface() : CanInterface({"mock"}) {}
MOCK_METHOD1(Write, bool(const lib::CanFrame& frame));
MOCK_METHOD1(Read, bool(lib::CanFrame* frame));
};
In the test code I want to pass an object to the Write method. Is there a way to do this with .With clause? It works with passing argument directly, but now with .With. The code compiles, but fails during execution - the size of the object is correct, but the data isn't.
This works:
EXPECT_CALL(can_, Write(expected_command_))
.WillOnce(Return(true));
This doesn't:
EXPECT_CALL(can_, Write(_))
.With(Args<0>(expected_command_))
.WillOnce(Return(true));
I admit that there may be something missing in the way the code sets the expected object.
I think the point is: The method Write() required a CanFrame argument passed by reference.
I suggest to use the Actions provided by GMock:
SetArgReferee - reference or value
SetArgPointee - pointer
You can find examples and much more here
However this solution works for me, I hope for you too ;)
EXPECT_CALL(can_, Write(_))
.WillOnce(SetArgReferee<0>(expected_command_));
or with the return value:
EXPECT_CALL(can_, Write(_))
.WillOnce(DoAll(SetArgReferee<0>(expected_command_), Return(true)));

Local variables in compile text stream (smalltalk)

I'm trying to overwrite the #new message in MyObject. The problem is that when the text gets compiled, the local variables, disp and oldNew are changed to t1 and t2 respectively (I'm using Squeak 4.3) and then it can't send oldNew to self.
I could change their names but I'm not sure that's a good idea.
Here's a basic outline of what I have:
MyObject class methodDict at: #new put:
(Object compilerClass new
compile: 'new
| disp oldNew |
oldNew := MyObject class methodDict at: #new.
disp := Dispatcher new.
^disp xxxViewedObject: self oldNew'
in: MyObject
notifying: nil
ifFail: []) generate
I'm not 100% sure if what I'm doing is the right way to do it so other ideas are welcome.
Edit: OK so I realise now it was looking for oldNew as a message in MyObject, but then how do I run the compiled method?
Apparently my problem was that MyObject was a subclass of ProtoObject and is now a subclass of Object.
Here's the code that seems to work after this change:
MyObject class methodDict at: #new put:
(Object compilerClass new
compile: 'new
| disp |
disp := Dispatcher new.
^disp xxxViewedObject: self basicNew initialize'
in: MyObject
notifying: nil
ifFail: []) generate
To evaluate your new generated compiled method you may use:
aCompiledMethod valueWithReceiver: nil arguments: #()
That's a nice way, however if you're experimenting problems I wrote a "code generator" based in a cross-Smalltalk library called Grease and which can be useful for you. It manages auto-comments, RBParser and Parser, authoring, and basic templating. All can be extended by anyone of course.
Generated methods are no different than others. So you simply send the method's selector to invoke it:
var := MyObject new.

Problem calling class methods (Q:1)

I'm trying to convert an old 'C' program containing some static methods into Obj-c but I'm having a few problems getting it to compile. In the header file I've got:
#interface Anneal : NSObject
...
...
+(float)approxInitT;
-(costType)simulatedAnnealing;
...
and in the implementation file, the two problem methods (also cut-down for brevity):
#implementation Anneal
+(float)approxInitT
{
float T=0.0;
int m2=0;
...
if(m2==0)
T = T_LIFESAVER;
else
T = T / m2 / log(initProb);
return T;
}
-(costType)simulatedAnnealing
{
float T;
...
if(Tset)
T=initialT;
else
T=[self approxInitT]; // error:incompatible types in assignment
}
Unfortunately I'm getting an "incompatible types in assignment" error even though 'T' and the return from the class method are both of type 'float'. While the code contains multiple source files (from which I'm expecting to hit a few more problems in the next few days), they're both in the same one.
The problem is obviously caused by an error in the way I'm calling 'approxInitT()' but a search of the internet hasn't uncovered any answers to my prob so far.
As a novice I don't have any experience in multi-model code OR using static/class methods, and I'd sure appreciate any help with this. Thanks in advance :-)
Class methods donot belong to any particular instance of a class. So, try passing the message to class itself -
T = [ Anneal approxInitT ];
self references an instance of a particular class, but as you are calling a class method (+approxInitT), you must send the message to your class: T=[Anneal
approxInitT]

smalltalk singleton pattern: how do I initialize the instance variables?

I'm having trouble in getting the singleton pattern to initialize a instance variable in smalltalk. (here is a link to another implementation for clarification)
this is what I have:
new
^UniqueInstance ifNil: [UniqueInstance := self basicNew.
UniqueInstance: instanceVar := Object new. ].
that last line (UniqueInstance: instanceVar := Object new.) doesn't work, but that's basically what I need to do: instantiate instanceVar as an Object before returning UniqueInstance back to the caller.
Notice that this 'new' method is used as a classinstantiation, and that libraries is a instance variable of UniqueIsntance (the isntance of the wanted class).
Can anyone point me in the right direction?
Try simpler:
YourClass class>>singleton
UniqueInstance ifNil: [UniqueInstance := self basicNew initialize].
^UniqueInstance
then on instance side of your class implement an appropriate #initialize method, for example:
YourClass>>initialize
someInstvar := someInitalValue.
^self
Update:: Name of the class method accessing the singleton varies, it can be #default, #current, or #singleton. I mostly use later.