GetChangedDocumentAsync returns null but should have a value - roslyn-code-analysis

My CodeFix returns a Document and I can trace it through Roslyn until GetChangeSolutionAsync. When I view in debugger ChangedDocument has a Document with the correct text. But the next line compares ChangedDocument == null and it is null and exits the routine returning null instead of my document.
I have stepped through GetChangedSoultionAsync and see it returning the correct value in the debugger but then see it return with null
protected async virtual Task<Solution> GetChangedSolutionAsync(CancellationToken cancellationToken)
{
var changedDocument = await GetChangedDocumentAsync(cancellationToken).ConfigureAwait(false);
if (changedDocument == null)
{
return null;
}
return changedDocument.Project.Solution;
}
In debugger changedDocument after the await is shown below
?changedDocument
Test0.vb
DocumentState: {Microsoft.CodeAnalysis.DocumentState}
FilePath: null
Id: (DocumentId, #860a1da9-991f-4262-9428-c50c7a9a912e - Test0.vb)
Name: "Test0.vb"
Project: TestProject
Services: {Microsoft.CodeAnalysis.DefaultTextDocumentServiceProvider}
SourceCodeKind: Regular
State: {Microsoft.CodeAnalysis.DocumentState}
But the if statement is true and the function returns null

Related

How to write tests for Either<> from dartz package in flutter

I am trying to write unit tests for a flutter app and I can't get this one test case to work correctly.
Here is the function returning Future<Either<WeatherData, DataError>>:
#override
Future<Either<WeatherData, DataError>> fetchWeatherByCity({required String city}) async {
try {
var response = await apiService.fetchWeatherByCity(city: city);
if (response.statusCode == 200) {
return Left(WeatherData.fromJson(jsonDecode(response.body)));
} else {
return Right(DataError(title: "Error", description: "Desc", code: 0, url: "NoUrl"));
}
} catch (error) {
AppException exception = error as AppException;
return Right(DataError(
title: exception.title, description: exception.description, code: exception.code, url: exception.url));
}
}
Here is the code where I am trying to write the unit test:
sut = WeatherRepositoryImpl(apiService: mockWeatherApiService);
test(
"get weather by city DataError 1 - Error 404 ",
() async {
when(mockWeatherApiService.fetchWeatherByCity(city: "city"))
.thenAnswer((_) async => Future.value(weatherRepoMockData.badResponse));
final result = await sut.fetchWeatherByCity(city: "city");
verify(mockWeatherApiService.fetchWeatherByCity(city: "city")).called(1);
expect(result, isInstanceOf<DataError>);
verifyNoMoreInteractions(mockWeatherApiService);
},
);
When I run this specific test, I receive this error:
Expected: <Instance of 'DataError'>
Actual: Right<WeatherData, DataError>:<Right(Instance of 'DataError')>
Which: is not an instance of 'DataError'
What I am not getting here? What should I be expecting from the function for the test to pass successfully?
You are directly using the result which is actually a wrapper and has a type of Either<WeatherData, DataError>.
You need to unwrap the value using the fold method on the result and then expect accordingly, So in your code you can do something like this to make it work:
final result = await sut.fetchWeatherByCity(city: "city");
result.fold(
(left) => fail('test failed'),
(right) {
expect(result, isInstanceOf<DataError>);
});
verifyNoMoreInteractions(mockWeatherApiService);
Hope this helps.
You need to either make the expected value a Right(), or extract the right side of the actual value. Doing either of those will match, but as it is, you're comparing a wrapped value with an unwrapped value.

How to properly test response.body is null in Flutter?

In my Flutter API I a getting an error
flutter: type 'Null' is not a subtype of type 'List' in type cast
when the response json list is empty. My API is written in Go. log.Println(mattersJSON) returns [1111 2222 3333 4444] and fmt.Println(string(mattersJSON)) returns null. This is expected as the query returns no records.
In Flutter, I have this code in my Api:
Future<List<Matter>> getMatters(BuildContext context) async {
List<Matter> matters = [];
try {
final response = await _helper.get(context, "/matters");
if (response.statusCode == 200) {
print(response.body);
if (response.body == null) {
return [];
}
print(response.body.length);
print('skipped test');
var parsed = json.decode(response.body) as List<dynamic>;
for (var matter in parsed) {
matters.add(Matter.fromJson(matter));
}
} else {
Navigator.pushNamed(context, RoutePaths.login);
return matters;
}
} catch (e) {
print(e);
return matters;
}
return matters;
}
The output is this:
flutter: null
flutter: 4
flutter: skipped test
flutter: type 'Null' is not a subtype of type 'List' in type cast
I'm tempted to assume that an empty response.body list will always have a length of 4 and that a response.body with records will always have have a length greater than 4. If so, then I could just test for a response.body.length > 4. However this is not elegant and probably fragile. I'm concerned that the error I'm seeing says the list is null and print(response.body) returns null but the response.body is not null.
How can I properly test for an empty response list and return []?
Assuming that you're talking about Response from package:http, then Response.body is non-nullable and cannot be null.
It sounds like response.body is the literal string 'null'. That would be reasonable if you're expecting JSON. Ultimately your problem is that you are performing an unconditional cast (as List<dynamic>). json.decode returns a dynamic type and not a List or a Map precisely because it might return a different types of objects, so the proper fix is to just check first:
var parsed = json.decode(response.body);
if (parsed is List<dynamic>) {
for (var matter in parsed) {
matters.add(Matter.fromJson(matter));
}
}
and then you don't need to explicitly check for response.body being the string 'null' or for json.decode returning null.

how do I work with file streams in dart/flutter?

I am new to dart/flutter programming. I have been trying to analyze the content of a file and return the result but couldn't. The code actually works when in the main function, but as soon as I take it out it doesn't work anymore. I have read the dart tutorial on futures, async, await, and streams as well as watched YouTube videos but still couldn't solve the problem. I believe my problem revolves around those concepts. Here is my code:
Future<String> r(String name) async {
var f = File(name);
var lines = f.readAsLines();
await lines
.then((line) => line.forEach((element) {
if (element.contains(RegExp(r'^hello'))) {
return element;
}
}))
.onError((error, stackTrace) => 'An error occured');
}
I was getting 2 errors:
The function name 'r' was underlined:
The body might complete normally, causing 'null' to be returned, but the return type is a potentially non-nullable type.
Try adding either a return or a throw statement at the end.
The variable 'element' was underlined:
The return type 'String' isn't a 'void', as required by the closure's context.
Thanks.
Your first error says that "Whatever happens, You have to return a String"
Your second error says that you are trying to return a String in a void function, As you see List. Foreach is a void function and you can't just return something in it because the return statement matches with the closest Function
So I rewrited you're code as following
Future<String> r(String name) async {
try {
var f = File(name);
var lines = await f.readAsLines();
for (var element in lines)
if (element.contains(RegExp(r'^hello'))) {
return element;
}
return "not found";
} catch (e) {
return 'An error occurred: $e';
}
}
Since you are using File and File.readAsLines I think it would be better to just wrap everything inside a try catch bloc k.

How is it possible that listening to Firestore collection allows to access data that I shouldn't have access to?

Given the below rule:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Nobody except superuser and member can see member data
match /Member/{id} {
allow get: if ((request.auth != null) && (id == request.auth.uid));
allow list: if ((request.auth != null) && (id == request.auth.uid));
//allow read: if ((request.auth != null) && (id == request.auth.uid));
allow update: if ((request.auth != null) && (id == request.auth.uid));
allow delete: if ((request.auth != null) && (id == request.auth.uid));
allow create: if ((request.auth != null) && (id == request.auth.uid));
}
}
}
And my data: Member collection.
document ID: PIijFvYPXQPSlheQxotvFvXW4VI2 which has some fields
document ID: QM6tGSkA2SRSPjHGIurDiARd6zv1 which has some fields
My observations that make sense:
1) Using the Rules playground
Simulation type: get
Location: /Member/PIijFvYPXQPSlheQxotvFvXW4VI2
Authenticate: false
Result:
Simulated read denied, due to : "allow get: if ((request.auth != null) && (id == request.auth.uid));" This makes total sense.
2) Using the Rules playground
Simulation type: get
Location: /Member/PIijFvYPXQPSlheQxotvFvXW4VI2
Authenticate: true
Provider: Google
Firebase UID: QM6tGSkA2SRSPjHGIurDiARd6zv1
Result:
Simulated read denied, due to : "allow get: if ((request.auth != null) && (id == request.auth.uid));" This makes total sense.
3) Using the Rules playground
Simulation type: get
Location: /Member/PIijFvYPXQPSlheQxotvFvXW4VI2
Authenticate: true
Provider: Google
Firebase UID: PIijFvYPXQPSlheQxotvFvXW4VI2
Result:
Simulated read allowed. This makes total sense.
4) In flutter,
Codesnippet 1:
await AbstractRepositoryS
ingleton.singleton
.userRepository()
.signInWithGoogle()
.then((value) async {
await AbstractRepositorySingleton.singleton
.memberRepository().valuesList().then((event) {
print("Success");
});
Codesnippet 2 (implementation of AbstractRepositorySingleton.singleton.memberRepository().valuesList())
Future<List<MemberModel>> valuesList() async {
return await MemberCollection.getDocuments().then((value) {
var list = value.documents;
return list.map((doc) => _populateDoc(doc)).toList();
});
}
Codesnippet 3:
final CollectionReference MemberCollection = Firestore.instance.collection('Member');
Action:
I run code snippet 1, which requests me to login onto my phone. I login with firebase UID = PIijFvYPXQPSlheQxotvFvXW4VI2, then a query for ALL members is run.
Result:
This fails, which ones again all makes sense.
My observations that make NO sense:
Codesnippet 1:
await AbstractRepositorySingleton.singleton
.userRepository()
.signInWithGoogle()
.then((value) async {
await AbstractRepositorySingleton.singleton
.memberRepository().values().listen((event) {
print("Success");
});
Codesnippet 2 (implementation of AbstractRepositorySingleton.singleton.memberRepository().values())
Stream<List<MemberModel>> values() {
return MemberCollection.snapshots().map((snapshot) {
return snapshot.documents
.map((doc) => _populateDoc(doc)).toList();
});
}
Action:
I run code snippet 1, which requests me to login onto my phone, I login with user with firebase ID = PIijFvYPXQPSlheQxotvFvXW4VI2,
then a LISTEN for ALL members is executed.
Result
This succeeds and the _populateDoc allows me to read all data fields from all members.
Basically it seems this mechanism allows me to read the entire collection, even for data where I should have no access to.
However, I'm sure I'm doing something wrong... but what.
Please advise. Many thanks.
One thing I noticed is an error occurring during the listen() method:
com.google.firebase.firestore.FirebaseFirestoreException: PERMISSION_DENIED: Missing or insufficient permissions.
Still for some reason I had 4 hits in the breakpoint in _populateDoc where I could happily read the member data from the doc.
After given this a bit extra thoughts, I've come to the conclusion this might have to do with local caching of the firestore data on my phone.
So I tried another phone, one where this particular app never ran before, I got the same error and I had 1 hit in the breakpoint in _populateDoc.
It's starting to make a bit sense to me. However, if someone could confirm this. Is this somewhere documented?

How to check whether a user exists in firebase cloudstore or not in a flutter application while reigisteration is done?

When i try to check whether a particular number exists in firebase collection or not I always get a null in return. What is the reason for that?
How can I overcome this issue so that the function _numberCheck() returns a Boolean value which I can use for further processing?
The code for the registration page is as follows:
Future<bool> _numberCheck(mobileno) async {
print("Start of the function");
db
.collection("transcriber_user_registeration")
.getDocuments()
.then((QuerySnapshot snapshot) {
snapshot.documents.forEach((f) async {
isPresent = true;
isPresent = false;
if ('${f.data['userid']}' == mobileno) {
setState(() {
isPresent = true;
});
} else {
setState(() {
isPresent = false;
});
}
});
});
// print(isPresent);
return isPresent;
}
For your case, you can try to use a query that only returns values that are not null. This way, in case it's not null, it will return true and if it's null, it will return false.
One example of how to achieve that - as better explained in this other question from the Community here - you can use the function hasAll(). This function returns only if all values are present. So, you would use it to load all the values to array, verifying this way, if they are not null - something like the below example.
!resource.data.keys().hasAll(['mobileno'])
There are other examples, such as using a String to compare values using the where() function, so you won't get the null values. More information on doing queries are available in this link.
I would recommend you to take a look at them and give these above options a try, to verify if they will help you. :)
Let me know if the information helped you!
You function returns null because you are returning isPresent without setting it to true, you only set isPresent = false, which means isPresent will be null otherwise, as variables hold objects references, so it will hold null if you didn't initialize it.
bool isPreset; // isPreset is null
isPreset = true; // isPreset is true
isPreset = false; // isPreset is false
If a variable lacks a value, it's value is null. Always initialize your variables to something.
Also, if f.data['userid'] is a String, you don't have to make it a String again by surrounding it with '${}'
Change your code to:
Future<bool> _numberCheck(mobileno) async {
QuerySnapshot snapshot = await db.collection("transcriber_user_registeration")
.getDocuments();
snapshot.documents.forEach((f) {
if (f.data['userid'] == mobileno) {
return false;
}
});
return true;
}
And call setState for the result of this function where you call it. Or just use a FutureBuilder to deal directly with the result and refresh your screen automatically.
If it returns true it means the query collection result is an empty collection or the if (f.data['userid'] == mobileno) is never true. So check the values on both.