Struct field reverts [duplicate] - unit-testing

This question already has answers here:
How to set and get fields in struct's method
(3 answers)
Assign a new value to a struct field
(2 answers)
Closed 5 years ago.
I'm playing with Go a bit but found this weird situation while doing some tests.
I'm using method in a struct to send a variable to another method that should change a field, but when I check it at the end, the field goes back to the first value, which has me confused.
func (this TVManager) sendMessage(message string) {
fmt.Println("5", this.connector)
payload := map[string]string {
"id": "0",
"type": "request",
"uri": "ssap://system.notifications/createToast",
"payload": "{'message': 'This is a message'}"}
this.connector.sendCommand(payload)
fmt.Println("4", this.connector)
}
This is the method I'm testing, it calls sendCommand of connector.
func (this MockConnector) sendCommand(payload map[string]string) {
fmt.Println("0", this)
this.last_command = payload
this.value = true
fmt.Println("0", this)
}
Which in the mock object I'm using is simply changing the value of this struct fields.
manager.sendMessage("This is a message")
fmt.Println("1", connector)
assert.Equal(t, expected, connector.last_command, "Command should be equal")
But when I check it, it goes back to internal. I set some prints to try an d track the values and they change the values as expected, but then it reverts.
1 {false map[]}
5 {false map[]}
0 {false map[]}
0 {true map[uri:ssap://system.notifications/createToast payload:{'message': 'This is a message'} id:0 type:request]}
4 {false map[]}
1 {false map[]}
--- FAIL: TestTVManagerSendsNotificationDownToConnector (0.00s)
This is just a small program I'm going over to learn some Go, so I appreciate any help anybody could give me.

You are passing the structures by value. This works fine so long as you are not modifying the structure, but if you do modify it you are actually only modifying a copy. To make this work you need to use pointers to the structures you need to modify.
Instead of:
func (this MockConnector) sendCommand(payload map[string]string)
Use:
func (this *MockConnector) sendCommand(payload map[string]string)
Also, it is considered a bad idea to use this (or self) as a receiver name in Go, as a receiver is not the same thing as a this pointer/reference in other languages.
Another best practice, is if one method for a given type needs a pointer receiver, all methods for that type should have pointer receivers. This is so that the method set remains consistent no matter if the value is a pointer or not.
See method sets, and these FAQ answers for more information.

Related

Use a method on a StateNotifier Riverpod for changing a bool [duplicate]

In the context of a Flutter 2.0.5 app whose state I'd like to manage with Riverpod, I thought I can declare a StateNotifierProvider like this:
import 'package:flutter_riverpod/flutter_riverpod.dart';
final counterProvider = StateNotifierProvider<CounterStateNotifier>((ref) => CounterStateNotifier());
class CounterStateNotifier extends StateNotifier<int> {
CounterStateNotifier([int count = 0]) : super(count);
void increment() => state++;
}
But Android Studio (and later the Dart compiler as well) complains about the line where I declare the counterProvider variable:
The type 'StateNotifierProvider' is declared with 2 type parameters, but 1 type arguments were given.
Removing the <CounterStateNotifier> type parameter in StateNotifierProvider<CounterStateNotifier> removes the error. However, attempting to read the provider and call its increment method (setting () => context.read(counterProvider).increment() as the onPressed of an ElevatedButton, then pressing the button) gives the following runtime error:
'increment'
method not found
Receiver: 0
Arguments: []
Why is context.read(counterProvider) returning the int state instead of the notifier? And what is the reason behind the type parameter error mentioned in the first part of my question?
I should mention that I'm running my app on the web (with flutter run -d Chrome).
As of Riverpod 0.14.0, State is the default value exposed by StateNotifierProvider.
The syntax for declaring your StateNotifierProvider is now as follows:
final counterProvider = StateNotifierProvider<CounterStateNotifier, int>((ref) => CounterStateNotifier());
Accessing functions now requires adding .notifier (accessing the StateNotifier itself):
context.read(counterProvider.notifier).increment();
And like you've noticed, you now access the state like so:
final count = context.read(counterProvider);
More on the changes here.
You may also use dynamic to accept any type if value for the StateNotifierProvider
final modelProvider =
StateNotifierProvider.autoDispose<ModelClassName, dynamic>(
(ref) => ModelClassName());

object query and remove parentheses in dart, flutter

Hello? I'm building an app using the flutter provider pattern. And I created a process to query the values ​​inside the object. I also have data in my model dart file.
Check the code below.
List<Device> _devices = [
Device(one: 'apple', two: 'iphone'),
Device(one: 'samsung', two: 'galaxy')
];
String Query(String value) {
return _media.where((medium) => medium.one == value)
.map((medium) => (medium.two)).toString();
Query("apple")
So, when I call that function, I expect iphone to be returned. But the results come in (iphne). Actually I know why. After all, the data returned is a List<Device> type. But what I want is to remove the parentheses by returning only the first value in the queried list(meaning only queried list, not the full list). In other words, I want to receive iphone, not (iphone). Currently, I am using substring removing the first and the final word, which seems to have some limitations. Is there any way to remove parentheses in that logic?
You have parentheses because you're calling .toString() on a list:
return _media.where((medium) => medium.one == value)
.map((medium) => (medium.two))
.toString();
To return just .two or the first found object, you just have to do:
return _media.firstWhere(
(medium) => medium.one == value, orElse: () => null)?.two;
That will return the value of .two of the first found object or null if nothing found.
Doc: Iterable.firstWhere()

Is there any option to use something similar to mockito argument captor?

we are using gopkg.in/mgo.v2/bson to talk with mongo, and its API populates passed structures instead returning results, for example:
func (p *Pipe) One(result interface{}) error {...
Problems occurs when I want to mock / test code which is using that. I want to both mock this execution and somehow get pupulated value in 'result'.
Currently test has:
query.EXPECT().One(gomock.Any())
So as you can see I dont get any value, I just configure gomock to check that when I run my method then query.One has to be called.
I cannot pass structure like
mystruct := MyStruct{}
query.EXPECT().One(&mystruct)
because mystruct in test code and in real code is different and verifing mock will fail (references are different). Im looking for something similar to mockito's argument captor:
https://static.javadoc.io/org.mockito/mockito-core/2.6.9/org/mockito/ArgumentCaptor.html
This can be achieved via Do.
Copy & Paste of Github example from poy.
var capturedArgs []int
someMock.
EXPECT().
SomeMethod(gomock.Any()).
Do(func(arg int){
capturedArgs = append(capturedArgs, arg)
})
Ref: https://github.com/golang/mock/pull/149
This project can help you: https://github.com/bouk/monkey.
You can replace a function and use a bool variable to check the use.
called := false
monkey.Patch(package.One, func(result interface{}) error {
if result == expected {
called := true
return nil
}
return errors.new("not expected")
})
Dont't forget to restore your original function.
defer monkey.Unpatch(package.One)

Retrieve element from array in Coldfusion

I get the following struct return from disqus.com API and I just don't know how to retrieve only the following "id" value in red using Coldfusion.
This is the full array returned.
{
"cursor":{
"prev":null,
"hasNext":false,
"next":"1213061503000000:1:0",
"hasPrev":false,
"total":null,
"id":"1213061503000000:1:0",
"more":false
},
"code":0,
"response":[
{
"category":"1",
"reactions":0,
"identifiers":[],
"forum":"bobross",
"title":"Donkeys live a long time",
"dislikes":0,
"isDeleted":false,
"author":"1",
"userScore":0,
"id":"2",
"isClosed":false,
"posts":0,
"link":null,
"likes":0,
"message":"\"Donkeys live a long time. None of you have ever seen a dead donkey.\"",
"ipAddress":"127.0.0.1",
"slug":"donkeys_live_a_long_time",
"createdAt":"2008-06-10T02:31:43"
},
{
"category":"1",
"reactions":0,
"identifiers":[
"my-identifier"
],
"forum":"bobross",
"title":"Happy Accidents",
"dislikes":0,
"isDeleted":false,
"author":"1",
"userScore":0,
"id":"1",
"isClosed":false,
"posts":76,
"link":null,
"likes":0,
"message":"\"If you've painted before you know that we don't make mistakes -- we have happy accidents.\"",
"ipAddress":"127.0.0.1",
"slug":"happy_accidents",
"createdAt":"2008-06-10T01:31:43"
}
]
}
Well: firstly, that's a JSON packet not an array, so you need to turn it into a CFML data structure by deserialising it, eg:
data = deserializeJson(jsonPacket);
Then you'll have a native CFML struct (not an array... the array is one of the values within the struct).
From there, you would access any given element the way one normally would with a CFML struct, using struct / array notation, or struct functions / etc.
To directly address the item you point out, it would be (given the code above has been run first):
data.response[1].id
However I suspect you don't really want to address just that one value? But without more detail as to what you're trying to do, it's difficult to answer other than exactly what you want.
If you wanted to get all the IDs, one could do this:
ids = [];
for (singleResponse in data.response){
arrayAppend(ids, singleResponse.id);
}
Or on ColdFusion 10 there's more options with how to iterate over arrays.
Again: clarify what you're trying to do, and we can help you do it.

How to call function from hashmap in Scala

I'm pretty new to scala and basically I want to have a couple of functions coupled to a string in a hashmap.
However I get an error at subscribers.get(e.key)(e.EventArgs); stating Option[EventArgs => Unit] does not take parameters...
Example code:
object Monitor {
val subscribers = HashMap.empty[String, (EventArgs) => Unit ]
def trigger(e : Event){
subscribers.get(e.key)(e.EventArgs);
}
def subscribe(key: String, e: (EventArgs) => Unit) {
subscribers += key -> e;
}
}
The get method of a Map gives you an Option of the value, not the value. Thus, if the key if found in the map, you get Some(value), if not, you get None. So you need to first "unroll" that option to make sure there is actually a value of a function which you can invoke (call apply on):
def trigger(e: Event): Unit =
subscribers.get(e.key).foreach(_.apply(e.EventArgs))
or
def trigger(e: Event): Unit =
subscribers.get(e.key) match {
case Some(value) => value(e.EventArgs)
case None =>
}
There are many posts around explaining Scala's Option type. For example this one or this one.
Also note Luigi's remark about using an immutable map (the default Map) with a var instead.
Since the get method returns Option, you can use 'map' on that:
subscribers.get(e.key).map(f => f(e.EventArgs))
or even shorter:
subscribers.get(e.key) map (_(e.EventArgs))
get only takes one argument. So subscribers.get(e.key) returns an Option, and you're trying to feed (e.EventArgs) to that Option's apply method (which doesn't exist).
Also, try making the subscribers a var (or choosing a mutable collection type). At the moment you have an immutable collection and an immutable variable, so your map cannot change. A more idiomatic way to declare it would be
var subscribers = Map[String, EventArgs => Unit]()
HashMap.get() in Scala works in a bit different way, than in Java. Instead of returning value itself, get() returns Option. Option is a special type, that can have 2 values - Some(x) and None. In first case it tells "there's some value with such a key in a map". In second case it tells "nope, there's nothing (none) for this key in a map". This is done to force programmers check whether map actually has an object or not and avoid NullPointerException, which appears so frequently in Java code.
So you need something like this:
def trigger(e: Event) {
val value = subscribers.get(e.key)
value match {
case None => throw new Exception("Oops, no such subscriber...")
case Some(f) => f(e.EventArgs)
}
}
You can find more info about Option type and pattern matching in Scala here.