Live example here.
type Activity = {
verb: string
}
type CommentActivity = {
verb: 'comment'
}
function doStuff (activity: Activity) {}
const commentActivity: CommentActivity = { verb: 'comment' }
const likeActivity: Activity = { verb: 'like' }
doStuff(likeActivity)
doStuff(commentActivity)
Fails with:
15: doStuff(commentActivity)
^ Cannot call `doStuff` with `commentActivity` bound to `activity` because string literal `comment` [1] is incompatible with string [2] in property `verb`.
References:
6: verb: 'comment' ^ [1]
2: verb: string ^ [2]
The error message is clear and I know how to work around this, but I don't understand why a string literal isn't considered a valid string?
This is an issue of property variance. If you have a function like doStuff with the type
(activity: Activity): void => {}
then it is perfectly valid for the function do to
function doStuff (activity: Activity) {
activity.verb = "some new verb";
}
and that 100% typechecks. What that means is that if
doStuff(commentActivity)
were allowed, doStuff would actually change the type of commentActivity, which is why this is throwing an error for you.
What you need to do is tell Flow that you will not be changing the value of .verb, essentially making it read-only inside of doStuff. To do this, you put a + before the name of the property.
type Activity = {
+verb: string
};
(On Flow/try)
Related
I'm returning an instance of class in a static method but flow is complaining about incompatible generic type. Is this a problem with flow or am I doing something wrong?
Code:
class Foo<T> {
var1: T
constructor(var1: T) {
this.var1 = var1
}
static staticMethod(var1: T) {
return new Foo(var1)
}
}
let x:Foo<number> = new Foo(1) // works
let y:Foo<number> = Foo.staticMethod(1) // doesn't work
Error:
let y:Foo<number> = Foo.staticMethod(1)
^ Cannot assign `Foo.staticMethod(...)` to `y` because `T` [1] is incompatible with number [2] in type argument `T` [3].
It seems like flow can't infer the type here, but it works fine if you annotate the return type.
Change
static staticMethod(var1: T) {
to
static staticMethod(var1: T): Foo<T> {
// I use this simple program:
public static Object convertToBean(Class type, Map map) {
BeanInfo beanInfo;
Object obj = null;
try {
beanInfo = Introspector.getBeanInfo(type);
obj = type.newInstance();
// When I debugging to here, I found that some properties is different from the variable the Object own. PropertyDescriptor changes charactor case when the variable is not in "String" type.
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor descriptor : propertyDescriptors) {
String propertyName = descriptor.getName();
if (map.containsKey(propertyName)) {
Object value = map.get(propertyName);
Object[] args = new Object[1];
args[0] = value;
descriptor.getWriteMethod().invoke(obj, args);
}
}
} catch (Exception ignored) {
}
return obj;
}
//Using BeanMap is the same question.
Finally I found the root cause.
The problem solved by changing “A01” to "a01".
The variable name must be strict camel rule. First character must be lower case, except first two characters are all in upper case, like "AD".
Because the setter and getter methods will generate in same pattern. so It'll be difficult to recognize the real name of one variable.
Given this Model:
public class RSS2Feed {
public var channel: RSS2FeedChannel?
public init() {}
}
public class RSS2FeedChannel {
public var title: String?
public var description: String?
public init() {}
}
What would I need to do in order to get the property names and values of an RSS2FeedChannel instance?
Here's what I'm trying:
let feed = RSS2Feed()
feed.channel = RSS2FeedChannel()
feed.channel?.title = "The Channel Title"
let mirror = Mirror(reflecting: feed.channel)
mirror.children.first // ({Some "Some"}, {{Some "The Channel Title...
for (index, value) in mirror.children.enumerate() {
index // 0
value.label // "Some"
value.value // RSS2FeedChannel
}
Ultimately, I'm trying to create a Dictionary that matches the instance, using reflection, but so far I'm unable to get the properties name and values of the instance.
Documentation says that:
The optional label may be used when appropriate, e.g. to represent the name of a stored property or of an active enum case, and will be used for lookup when Strings are passed to the descendant method.
Yet I only get a "Some" string.
Also, the value property is returning a string with the Type RSS2FeedChannel when I would expect each children to be "An element of the reflected instance's structure."!
When i understand correct this should solve ur problem:
func aMethod() -> Void {
let feed = RSS2Feed()
feed.channel = RSS2FeedChannel()
feed.channel?.title = "The Channel Title"
// feed.channel?.description = "the description of your channel"
guard let channel = feed.channel else {
return
}
let mirror = Mirror(reflecting: channel)
for child in mirror.children {
guard let key = child.label else {
continue
}
let value = child.value
guard let result = self.unwrap(value) else {
continue
}
print("\(key): \(result)")
}
}
private func unwrap(subject: Any) -> Any? {
var value: Any?
let mirrored = Mirror(reflecting:subject)
if mirrored.displayStyle != .Optional {
value = subject
} else if let firstChild = mirrored.children.first {
value = firstChild.value
}
return value
}
just some little changes for swift 3:
private func unwrap(_ subject: Any) -> Any? {
var value: Any?
let mirrored = Mirror(reflecting:subject)
if mirrored.displayStyle != .optional {
value = subject
} else if let firstChild = mirrored.children.first {
value = firstChild.value
}
return value
}
You can use the descendent method on the Mirror object to get this information. It will return nil if the values aren't found or the optionals contain no value.
let mirror = Mirror(reflecting: feed.channel)
let child1 = mirror.descendant("Some", "title") // "The Channel Title"
// or on one line
let child3 = Mirror(reflecting: feed).descendant("channel", "Some", "title")
How do I parse query strings safely in Dart?
Let's assume I have q string with the value of:
?page=main&action=front&sid=h985jg9034gj498g859gh495
Ideally the code should work both in the server and client, but for now I'll settle for a working client-side code.
The simpler, the better. Look for the splitQueryString static method of class Uri.
Map<String, String> splitQueryString(String query, {Encoding encoding: UTF8})
Returns the query split into a map according to the rules specified for
FORM post in the HTML 4.01 specification section 17.13.4. Each key and value
in the returned map has been decoded. If the query is the empty string an
empty map is returned.
I have made a simple package for that purpose exactly: https://github.com/kaisellgren/QueryString
Example:
import 'package:query_string/query_string.dart');
void main() {
var q = '?page=main&action=front&sid=h985jg9034gj498g859gh495&enc=+Hello%20&empty';
var r = QueryString.parse(q);
print(r['page']); // "main"
print(r['asdasd']); // null
}
The result is a Map. Accessing parameters is just a simple r['action'] and accessing a non-existant query parameter is null.
Now, to install, add to your pubspec.yaml as a dependency:
dependencies:
query_string: any
And run pub install.
The library also handles decoding of things like %20 and +, and works even for empty parameters.
It does not support "array style parameters", because they are not part of the RFC 3986 specification.
I done that just like this:
Map<String, String> splitQueryString(String query) {
return query.split("&").fold({}, (map, element) {
int index = element.indexOf("=");
if (index == -1) {
if (element != "") {
map[element] = "";
}
} else if (index != 0) {
var key = element.substring(0, index);
var value = element.substring(index + 1);
map[key] = value;
}
return map;
});
}
I took it from splitQueryString
I'm trying to verify a method call using Moq, but I can't quite get the syntax right. Currently, I've got this as my verify:
repository.Verify(x => x.ExecuteNonQuery("fav_AddFavorites", new
{
fid = 123,
inputStr = "000456"
}), Times.Once());
The code compiles, but the test fails with the error:
Expected invocation on the mock once, but was 0 times:
x => x.ExecuteNonQuery("fav_AddFavorites", new <>f__AnonymousType0<Int32, String>(123, "000456"))
No setups configured.
Performed invocations:
IRepository.ExecuteNonQuery("fav_AddFavorites", { fid = 123, inputStr = 000456 })
How can I verify the method call and match the method parameters for an anonymous type?
UPDATE
To answer the questions:
I am trying to verify both that the method was called and that the parameters are correct.
The signature of the method I'm trying to verify is:
int ExecuteNonQuery(string query, object param = null);
The setup code is simply:
repository = new Mock<IRepository>();
UPDATE 2
It looks like this is a problem with Moq and how it handles anonymous types in .Net. The code posted by Paul Matovich runs fine, however, once the code and the test are in different assemblies the test fails.
This Passes
public class Class1
{
private Class2 _Class2;
public Class1(Class2 class2)
{
_Class2 = class2;
}
public void DoSomething(string s)
{
_Class2.ExecuteNonQuery(s, new { fid = 123, inputStr = "000456" });
}
}
public class Class2
{
public virtual void ExecuteNonQuery(string s, object o)
{
}
}
/// <summary>
///A test for ExecuteNonQuery
///</summary>
[TestMethod()]
public void ExecuteNonQueryTest()
{
string testString = "Hello";
var Class2Stub = new Mock<Class2>();
Class1 target = new Class1(Class2Stub.Object);
target.DoSomething(testString);
Class2Stub.Verify(x => x.ExecuteNonQuery(testString, It.Is<object>(o => o.Equals(new { fid = 123, inputStr = "000456" }))), Times.Once());
}
##Update##
That is strange, it doesn't work in different assemblies. Someone can give us the long definition about why the object.equals from different assemblies behaves differently, but for different assemblies, this will work, any variance in the object values will return a different hash code.
Class2Stub.Verify(x => x.ExecuteNonQuery(testString, It.Is<object>(o => o.GetHashCode() == (new { fid = 123, inputStr = "000456" }).GetHashCode())), Times.Once());
One option is to "verify" it in a Callback. Obviously this needs to be done at Setup time, e.g.:
aMock.Setup(x => x.Method(It.IsAny<object>())).Callback<object>(
(p1) =>
{
dynamic o = p1;
Assert.That(o.Name, Is.EqualTo("Bilbo"));
});
None of the answers are great when your test assembly is different than the system under test's assembly (really common). Here's my solution that uses JSON serialization and then strings comparison.
Test Helper Function:
using Newtonsoft.Json;
public static class VerifyHelper
{
public static bool AreEqualObjects(object expected, object actual)
{
var expectedJson = JsonConvert.SerializeObject(expected);
var actualJson = JsonConvert.SerializeObject(actual);
return expectedJson == actualJson;
}
}
Example System Under Test:
public void DoWork(string input)
{
var obj = new { Prop1 = input };
dependency.SomeDependencyFunction(obj);
}
Example Unit Test:
var expectedObject = new { Prop1 = "foo" };
sut.DoWork("foo");
dependency.Verify(x => x.SomeDependencyFunction(It.Is<object>(y => VerifyHelper.AreEqualObjects(expectedObject, y))), Times.Once());
This solution is really simple, and I think makes the unit test easier to understand as opposed to the other answers in this thread. However, because it using simple string comparison, the test's anonymous object has to be set up exactly the same as the system under the test's anonymous object. Ergo, let's say you only cared to verify the value of a single property, but your system under test sets additional properties on the anonymous object, your unit test will need to set all those other properties (and in the same exact order) for the helper function to return true.
I created a reusable method based on Pauls answer:
object ItIsAnonymousObject(object value)
{
return It.Is<object>(o => o.GetHashCode() == value.GetHashCode());
}
...
dependency.Verify(
x => x.SomeDependencyFunction(ItIsAnonymousObject(new { Prop1 = "foo" })),
Times.Once());
Also, this can be used for property name case-insensitive comparison:
protected object ItIsAnonymousObject(object value)
{
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
return It.Is<object>(o => JsonSerializer.Serialize(o, options) == JsonSerializer.Serialize(value, options));
}