How to use object comparision for custom objects in dart/flutter - list

I have a collection of dishes.
I want to retrieve all restaurant who have a specific list of dish in his menu.
My data model is this:
restaurant---->rest1
| |-->menu
| | --> 1: true
| | --> 2: true
| | --> 3: true
|--->rest2
| |-->menu
| | --> 1: true
| | --> 2: true
| | --> 3: true
|--->rest3
| |-->menu
| | --> 1: true
my list of dishes is [1,2] for this reason I want to retrieve only rest1 and rest2
my code is this:
Future loadRestaurantsByDishes({List idPiatti})async{
idPiatti.forEach((element) async {
dynamic result2 = await _restaurantServices.getRestaurantOfDish(id_piatto: element["dishId"].toString());
rest.add( result2);
});
if(rest.length >0){
List<RestaurantModel> mom = [];
List<RestaurantModel> temp = [];
rest.forEach((item) {
if(mom.isEmpty){
mom.addAll(item);
}else{
temp.addAll(item);
mom.removeWhere((element) => !temp.contains(element));
temp = [];
}
});
notifyListeners();
}
}
Future<List<RestaurantModel>> getRestaurantOfDish({String id_piatto}) async =>
_firestore.collection(collection).where("menu."+id_piatto, isEqualTo: true).get().then((result) {
List<RestaurantModel> restaurants = [];
for (DocumentSnapshot restaurant in result.docs) {
restaurants.add(RestaurantModel.fromSnapshot(restaurant));
}
return restaurants;
});
My idea is to retrieve all resturant who made a specific dish and after retrieve the common elements between those lists in order to retrieve the only restaur ant which have all of them.
The problem is that mom in the first statement is equal to item, but when I run mom.removeWhere((element) => !temp.contains(element)); it returns an empty list.
Where I'm getting wrong?
Thank you

While comparing objects of custom classes you have created, you must override the == override and the hashCode function.
You can use the below explained method for you own custom classes in order to compare two of them using the == operator.
Try running this inside a DartPad.
class Cat {
String id;
Cat(this.id);
#override
bool operator == (Object other){
return other is Cat && id == other.id;
}
#override
int get hashCode => id.hashCode;
#override
String toString() => '{ id: $id }';
}
void main() {
List l1 = [Cat('1'), Cat('2')];
List l2 = [Cat('2'), Cat('3')];
List l3 = [Cat('2'), Cat('4')];
l1.removeWhere((item) => !l2.contains(item));
l1.removeWhere((item) => !l3.contains(item));
print(l1);
}

Related

[DART]- Check if a value exists in a list of objects

I've got an Abstract class named QuizzAnswer and I've a class named QuizzAnswerMCQ which extends QuizzAnswer class.
abstract class QuizzAnswer extends Equatable {}
class QuizzAnswerMCQ extends QuizzAnswer {
String optionId;
bool isSelected;
QuizzAnswerMCQ({required this.optionId, required this.isSelected});
#override
List<Object?> get props => [optionId, isSelected];
Map<String, dynamic> toJson() => {
"option_id": optionId,
"is_selected": isSelected,
};
}
and I've got a list which is of type QuizzAnswerMCQ
List<QuizzAnswerMCQ> quizAnswerList=[];
and I add items to the list
quizAnswerList.add(QuizzAnswerMCQ(
optionId: event.optionId, isSelected: event.optionValue));
what I want to do is to check if the optionId is already there in the list or not so I wrote this,
if(quizAnswerList.map((item) => item.optionId).contains(event.optionId)){
print ('EXISTTTTSSSSS');
}else{
print('DOESNT EXISTTTT');
}
Even though the optionId is there,I still get the output 'DOESNT EXISTTTT'.Please help!!!
Do this
if (quizAnswerList
.where((element) => element.optionId == event.optionId)
.isNotEmpty) {
print ('EXISTTTTSSSSS');
}
else{ print('DOESNT EXISTTTT'); }
the .where() method checks and creates a list so if it's not empty then that item exists
You can use firstWhere like this
result = quizAnswerList.firstWhere((item) => item.optionId == your_id);
or checking from other List
result = quizAnswerList.firstWhere((item) => otherList.contains(item));
then
if(result.length > 0){
print ('');
}else{
print(');
}
Official doc here

adding record from one List to another List

In List One, I am getting some items. Each time those items are changing. Sometimes, I can get more than one record in the List.
In a second List, I would like to store all the data of List One. So, I can then display all the items of List Two.
To make it more clear.
List One = "/temp/file1.jpeg"
List Two = "/temp/file1.jpeg"
List One = "/temp/file2.jpeg"
List Two = "/temp/file1.jpeg,/temp/file2.jpeg"
I have tried this
void _openDocumentFileExplorer({fileType: FileType.custom}) async {
setState(() => _loadingPath = true);
try{
_paths = (await FilePicker.platform.pickFiles(
type: fileType,
allowMultiple: true,//_multiPick,
allowedExtensions: ['pdf']))?.files;
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
} catch (ex) {
print('$ex');
}
if (!mounted) return;
setState(() {
_loadingPath = false;
_fileName = _paths != null ?
_paths!.map((e) => e.name).toString() : '...';
});
}
ListView.separated(
itemCount:
_paths != null && _paths!.isNotEmpty
? _paths!.length
: 1,
itemBuilder:
(BuildContext context, int index) {
final bool isMultiPath =
_paths != null && _paths!.isNotEmpty;
final String name = _paths!
.map((e) => e.name)
.toList()[index];
//filesGB store the full path + the file name
final filesGB = _paths!
.map((e) => e.path)
.toList()[index]
.toString();
print (filesGB);
_paths?.addAll(allFiles!.map((e) ));
allFiles.addAll(filesGB.toList());
allFiles.addAll(filesGB);
// allFilesV2.addAll(filesGB);
but it does not work. I am getting this error message.
"The argument type 'String' can't be assigned to the parameter type 'Iterable'"
Please, do you have any suggestion?
I think you can use SPREAD OPERATOR (...) using a triple dot for merging one array into another.
For example:
List list1= ["/temp/file1.jpeg"];
List list2 = [];
after some time
list1 = ["/temp/file2.jpeg"];
so whenever your list one change do
list2 = [...list2,...list1];
print(list2);
output: ["/temp/file1.jpeg","/temp/file2.jpeg"]
I think it would help.

I'm not able to test my sails.js controller with chai and sinon

I have a controller Acounts with a method sum, and a service file named validation with an object register. This object has a method validate that validates the form provided and returns a Boolean.
Controller
sum: function(req, res) {
//validate form with a validation service function
const validator = new validation.register();
let check = validator.validate(req.body.form);
let count = 0;
if (check) {
count += 1;
} else {
count -= 1;
}
res.send(count);
},
test
//imports
const chai = require("chai");
const expect = chai.expect;
const sinon = require("sinon");
const util = require('util'); // to print complex objects
const acountsC = require("../../../api/controllers/AcountsController.js");
describe("AcountsController", function() {
describe("sum", function() {
let req = {
body: {
form: {}
}
}
let res = {
send: sinon.spy()
}
let validation = {
register: {
validate: function() {}
}
}
let stub_validate = sinon.stub(validation.register, "validate").returns(true);
it("count should be 1 when validation is true", function() {
acountsC.sum(req, res);
expect(count).to.equal(1);
});
});
});
test log
AcountsController
sum
1) count should be 1 when validation is true
0 passing (5s)
1 failing
1) AcountsController
sum
count should be 1 when validation is true:
ReferenceError: count is not defined
note
I understand that the test is supposed to execute the piece of code we are calling, while replacing the external functions called in that piece of code(The controller) making it return whatever we set. If the test is executing that piece of code, why I can't access any variables created in the controller?
I've tried by spying res.send(), and check if it was called with a 1. I didn't succeed.
I searched everywhere how to perform an assertion to a variable, but I found nothing. :(
hope you can help
Here is the unit test solution:
accountController.js:
const validation = require('./validation');
class AccountController {
sum(req, res) {
const validator = new validation.register();
const check = validator.validate(req.body.form);
let count = 0;
if (check) {
count += 1;
} else {
count -= 1;
}
res.send(count);
}
}
module.exports = AccountController;
validation.js:
class Register {
validate() {}
}
module.exports = {
register: Register,
};
accountController.test.js:
const AccountController = require('./accountController');
const sinon = require('sinon');
const validation = require('./validation');
describe('60182912', () => {
afterEach(() => {
sinon.restore();
});
describe('#sum', () => {
it('should increase count and send', () => {
const registerInstanceStub = {
validate: sinon.stub().returns(true),
};
const registerStub = sinon.stub(validation, 'register').callsFake(() => registerInstanceStub);
const accountController = new AccountController();
const mRes = { send: sinon.stub() };
const mReq = { body: { form: {} } };
accountController.sum(mReq, mRes);
sinon.assert.calledWithExactly(mRes.send, 1);
sinon.assert.calledOnce(registerStub);
sinon.assert.calledWithExactly(registerInstanceStub.validate, {});
});
it('should decrease count and send', () => {
const registerInstanceStub = {
validate: sinon.stub().returns(false),
};
const registerStub = sinon.stub(validation, 'register').callsFake(() => registerInstanceStub);
const accountController = new AccountController();
const mRes = { send: sinon.stub() };
const mReq = { body: { form: {} } };
accountController.sum(mReq, mRes);
sinon.assert.calledWithExactly(mRes.send, -1);
sinon.assert.calledOnce(registerStub);
sinon.assert.calledWithExactly(registerInstanceStub.validate, {});
});
});
});
Unit test results with coverage report:
60182912
#sum
✓ should increase count and send
✓ should decrease count and send
2 passing (10ms)
----------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 50 | 100 |
accountController.js | 100 | 100 | 100 | 100 |
validation.js | 100 | 100 | 0 | 100 |
----------------------|---------|----------|---------|---------|-------------------
source code: https://github.com/mrdulin/expressjs-research/tree/master/src/stackoverflow/60182912
The problem was the lifecycle file I created trusting in sails docs. That documentation is for integrated testing due to the fact that it lifts sails before any other test. This is quite slow while unit tests should be fast. Erasing that file was enough to test the controller successfully. Otherwise sails messes up with the tests in a way I don't even fully understand. I suppose it is due to sails making services globally available. So when my controller calls for validation service, this one returns some default and not what the stub says it should return.
UPDATE:
I managed to make it work. When lifting sails before testing, only the tested controller should be require, services and models shouldn't.

Unit test ClientProxy in Nestjs

In Nestjs, I try to mock a ClientProxy but I receive a typing error telling me that I need to define all properties of ClientProxy class. Of course, I don't want to mock every property of this Class.
Any idea on how to solve this?
Here's a simplified piece of code:
service.ts
#Injectable()
export class SimulationsService {
constructor() {}
#Client({
transport: Transport.NATS,
options: {
url: env.nats,
user: env.usernats,
pass: env.passnats,
},
})
simulationClient: ClientProxy;
method1(){
this.simulationClient.send('simulatePattern', simulation)
.pipe(
map(sim=>{
//SOME CODE
return sim;
})
});
}
service.spec.ts
describe('method1', () => {
it('should return a processed Simulation', async () => {
jest.spyOn(
service,
'simulationClient',
'get',
).mockImplementation(()=>{
return {send() {
return of(simulationMock as Simulation);
}}
});
});
expect(await service.update('test', unfedSimulationMock)).toEqual(simulationMock);
});
});
Error output :
Type '{ send(): Observable; }' is missing the following properties from type 'ClientProxy': connect, close, routingMap, emit, and 7 more.
Here is a solution:
export interface ClientProxy {
send(pattern: string, simulation: any): any;
connect(): any;
close(): any;
routingMap(): any;
}
I simplify the code for service.ts:
// tslint:disable-next-line: interface-name
export interface ClientProxy {
send(pattern: string, simulation: any): any;
connect(): any;
close(): any;
routingMap(): any;
}
export class SimulationsService {
constructor(private simulationClient: ClientProxy) {}
public method1() {
const simulation = {};
this.simulationClient.send('simulatePattern', simulation);
}
}
Unit test, partial mock ClientProxy which means we can mock specific methods without the type error.
import { SimulationsService, ClientProxy } from './service';
import { mock } from '../../__utils';
const simulationClientMock = mock<ClientProxy>('send');
// Argument of type '{ send: Mock<any, any>; }' is not assignable to parameter of type 'ClientProxy'.
// Type '{ send: Mock<any, any>; }' is missing the following properties from type 'ClientProxy': connect, close, routingMap
// const simulationClientMock = {
// send: jest.fn()
// };
const service = new SimulationsService(simulationClientMock);
describe('SimulationsService', () => {
describe('#method1', () => {
it('t1', () => {
simulationClientMock.send.mockReturnValueOnce('mocked data');
service.method1();
expect(simulationClientMock.send).toBeCalledWith('simulatePattern', {});
});
});
});
__util.ts:
type GenericFunction = (...args: any[]) => any;
type PickByTypeKeyFilter<T, C> = {
[K in keyof T]: T[K] extends C ? K : never;
};
type KeysByType<T, C> = PickByTypeKeyFilter<T, C>[keyof T];
type ValuesByType<T, C> = {
[K in keyof T]: T[K] extends C ? T[K] : never;
};
type PickByType<T, C> = Pick<ValuesByType<T, C>, KeysByType<T, C>>;
type MethodsOf<T> = KeysByType<Required<T>, GenericFunction>;
type InterfaceOf<T> = PickByType<T, GenericFunction>;
type PartiallyMockedInterfaceOf<T> = {
[K in MethodsOf<T>]?: jest.Mock<InterfaceOf<T>[K]>;
};
export function mock<T>(...mockedMethods: Array<MethodsOf<T>>): jest.Mocked<T> {
const partiallyMocked: PartiallyMockedInterfaceOf<T> = {};
mockedMethods.forEach(mockedMethod => (partiallyMocked[mockedMethod] = jest.fn()));
return partiallyMocked as jest.Mocked<T>;
}
Unit test result with 100% coverage:
PASS src/stackoverflow/57960039/service.spec.ts
SimulationsService
#method1
✓ t1 (4ms)
----------------------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------------------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
src | 100 | 100 | 100 | 100 | |
__utils.ts | 100 | 100 | 100 | 100 | |
src/stackoverflow/57960039 | 100 | 100 | 100 | 100 | |
service.ts | 100 | 100 | 100 | 100 | |
----------------------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 3.234s, estimated 6s
Here is the completed demo: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/57960039

Grails Unit testing a function with session object

I having a Controller like
def testFunction(testCommand cmdObj) {
if (cmdObj.hasErrors()) {
render(view: "testView", model: [cmdObj:cmdObj])
return
} else {
try {
testService.testFunction(cmdObj.var1, cmdObj.var2, session.user.username as String)
flash.message = message(code: 'message')
redirect url: createLink(mapping: 'namedUrl')
} catch (GeneralException error) {
render(view: "testView", model: [cmdObj:cmdObj])
return
}
}
}
For the above controller function I having a Unit test function like:
def "test function" () {
controller.session.user.username = "testUser"
def testCommandOj = new testCommand(
var1:var1,
var2:var2,
var3:var3,
var4:var4
)
testService service = Mock(testService)
controller.testService = service
service.testFunction(var2,var3,var4)
when:
controller.testFunction(testCommandOj)
then:
view == "testView"
assertTrue model.cmdObj.hasErrors()
where:
var1 | var2 | var3 | var4
"testuser" | "word#3" | "word#4" | "word#4"
}
When running this test function I getting the error like Cannot set property 'username' on null object, means I couldn't able to set up the session object. Can someone help to fix this. Thanks in advance
Since you are doing the Grails controller's unit test, you can directly assign the variables into the session object as you do for params this way in your setup: block. I recommend you to just assign the User object in session first and then it will be fine: I have slightly modified your code:
def "test function" () {
setup:
User user = new User(username:'requiredUserName').save(flush:true,failOnError:true)
session.user = user
def testCommandOj = new testCommand(
var1:var1,
var2:var2,
var3:var3,
var4:var4
)
testService service = Mock(testService)
controller.testService = service
service.testFunction(var2,var3,var4)
when:
controller.testFunction(testCommandOj)
then:
view == "testView"
assertTrue model.cmdObj.hasErrors()
where:
var1 | var2 | var3 | var4
"testuser" | "word#3" | "word#4" | "word#4"
}
This should be working fine now.The only problem was you did not assign the User object in session.