How can I create a fake with FakeItEasy that allows different return values on successive calls. This is one example of what I would like to be able to do:
var enumerator = A.Fake<IDictionaryEnumerator>();
A.CallTo(() => enumerator.MoveNext()).Returns(true); //Expected value for first call
A.CallTo(() => enumerator.Key).Returns("key1");
A.CallTo(() => enumerator.Value).Returns("value1");
A.CallTo(() => enumerator.MoveNext()).Returns(false); //Expected value for second call
Assert.IsTrue(enumerator.MoveNext()); //Fails
Assert.IsFalse(enumerator.MoveNext());
The assertion will fail since it the last set up of MoveNext will overwrite the first one.
Is it possible to do what I want in FakeItEasy?
.
[Edit]
Clarified the original question's example and provided a working example below.
Based on Patrik's answer this code shows how you can set up the fake. The trick is to reverse all setups and use Once().
var enumerator = A.Fake<IDictionaryEnumerator>();
A.CallTo(() => enumerator.MoveNext()).Returns(false).Once();
A.CallTo(() => enumerator.MoveNext()).Returns(true).NumberOfTimes(2);
A.CallTo(() => enumerator.Key).Returns("key2").Once();
A.CallTo(() => enumerator.Value).Returns("value2").Once();
A.CallTo(() => enumerator.Key).Returns("key1").Once();
A.CallTo(() => enumerator.Value).Returns("value1").Once();
while(enumerator.MoveNext())
{
Debug.WriteLine(enumerator.Key + ": "+ enumerator.Value);
}
This will print:
key1: value1
key2: value2
I'm not entirely sure that I understand what you mean, the code you supplied will always fail. However if you mean that you want it to return true the second time it's called it can be done. There are a couple of different ways that I can think of, two of them are:
A.CallTo(() => enumerator.MoveNext()).ReturnsNextFromSequence(false, true);
The other way is:
A.CallTo(() => enumerator.MoveNext()).Returns(true);
A.CallTo(() => enumerator.MoveNext()).Returns(false).Once();
Edit:
On second though I guess I understand your question better, what you want to happen is that MoveNext should return true the first time and false the second time? If that's the case just change the orders of the values in the examples above.
FakeItEasy does not use a record/replay model and you are correct in that the latest configured rule has precedence over any earlier specified rules. That's why you have to specify repeat - ".Once()" - on the latest configuration for it only to be valid once.
There are many reasons why the latest has precedence, one of the most important ones is that it lets you set up a default return value in the setup of your fixture and override it to return specific values in some of your tests, this is impossible when using a record/replay model.
The OP's example based on Patrik's answer is fine ... but tedious if the sequence grows large. To supplement that answer consider that even though fake/mock examples most often show a bunch of straight line code to Arrange themselves you actually have the full power of a programming language at your command. Conditionals, loops, and even procedures.
So consider the following:
public static void AFakeDictionaryEnumeratorReturns(
IDictionaryEnumerator enumerator, params object[] pairs)
{
if (0 != pairs.Length % 2)
throw new ArgumentException("pairs must have even number of elements", "pairs");
int n = pairs.Length / 2;
A.CallTo(() => enumerator.MoveNext()).Returns(false).Once();
A.CallTo(() => enumerator.MoveNext()).Returns(true).NumberOfTimes(n);
for (int i = pairs.Length; i > 0; i -= 2)
{
A.CallTo(() => enumerator.Key).Returns(pairs[i - 2]).Once();
A.CallTo(() => enumerator.Value).Returns(pairs[i - 1]).Once();
}
}
and now the test becomes:
var enumerator = A.Fake<IDictionaryEnumerator>();
AFakeDictionaryEnumeratorReturns(enumerator,
"key1", "value1", "key2", "value2", "key3", "value3");
var keys = new List<object>();
var values = new List<object>();
while (enumerator.MoveNext())
{
keys.Add(enumerator.Key);
values.Add(enumerator.Value);
}
Assert.Equal(new List<object> { "key1", "key2", "key3" }, keys);
Assert.Equal(new List<object> { "value1", "value2", "value3" }, values);
(An IDictionaryEnumerator deals in pairs, so this example isn't as clearly beneficial as it could be. For a standard IEnumerator<T> a single static generic method would serve for a whole bunch of different enumerators.)
Related
I am using Laravel 5.5.13.
Thanks to awesome help from awesome member of SO I currently get nested (and repeated) data by doing this:
public function show(Entity $entity)
{
return $entity->with([
'comments' => function($query) {
$query->with([
'displayname',
'helpfuls' => function($query) {
$query->with('displayname');
}
]);
},
'thumbs' => function($query) {
$query->with('displayname');
}
])->firstOrFail();
}
This gives me example data like this: https://gist.githubusercontent.com/blagoh/ee5e70dfe35aa5c68b2d445c63887aaa/raw/a0612fb770a27eaacfbb1e87987aa4fd8902a8a3/nested.json
However I want to flatten it to this: https://gist.github.com/blagoh/7076be06c400d04941a0593267e11e81 - look at the version diff we see the changes:
https://gist.github.com/blagoh/7076be06c400d04941a0593267e11e81/revisions#diff-cb567797700e4d4b63b106653162c671R15
We see line 15 is now "helpful_ids": [] and has just array of ids, and then all displaynames and helpfuls were moved to top of array on line 45 and 78.
Is it possible to flatten this data, while keeping same query performance (or better)?
Let's say I have a giant table, something like:
test.test[1].testing.test.test_test
The table isn't guaranteed to exist. Neither are the tables containing it. I would like to just be able to do:
if test.test[1].testing.test.test_test then
print("it exits!")
end
But of course, this would give me an "Attempt to index ? (a nil value)" error if any of the indices aren't yet defined. So many times, I'll end up doing something like this:
if test then
if test.test then
if test.test[1] then
if test.test[1].testing then -- and so on
Is there a better, less-tedious way to accomplish this?
You can write a function that takes a list of keys to look up and does whatever action you want if it finds the entry. Here's an example:
function forindices(f, table, indices)
local entry = table
for _,idx in ipairs(indices) do
if type(entry) == 'table' and entry[idx] then
entry = entry[idx]
else
entry = nil
break
end
end
if entry then
f()
end
end
test = {test = {{testing = {test = {test_test = 5}}}}}
-- prints "it exists"
forindices(function () print("it exists") end,
test,
{"test", 1, "testing", "test", "test_test"})
-- doesn't print
forindices(function () print("it exists") end,
test,
{"test", 1, "nope", "test", "test_test"})
As an aside, the functional programming concept that solves this kind of problem is the Maybe monad. You could probably solve this with a Lua implementation of monads, though it wouldn't be very nice since there's no syntactic sugar for it.
You can avoid raising errors by setting an __index metamethod for nil:
debug.setmetatable(nil, { __index=function () end })
print(test.test[1].testing.test.test_test)
test = {test = {{testing = {test = {test_test = 5}}}}}
print(test.test[1].testing.test.test_test)
You also use an empty table:
debug.setmetatable(nil, { __index={} })
Current question is relative with next one, but now I need to read the data from database instead of insert.
I have next three case classes:
case class A (id: Long, bList: List[B])
case class B (id: Long, aId: cList: List[C])
case class C (id: Long, bId: Long)
And query with two leftJoin functions and incomingAId for filtering aTable results:
val query = (for {
((aResult,bResult),cResult) <- aTable.filter(_.id === incomigAId)
.joinLeft(bTable).on(_.id === _.aId)
.joinLeft(cTable).on(_._2.map(_.id) === _.bId)
} yield ((aResult,bResult),cResult)).result.transactionally
Next query works and the result looks valid, but isn't easy to handle it to the case classes. Also, executionResult has Seq[Nothing] type and process of mapping requires something like that:
database.run(query).map{ executionResult =>
executionResult.map { vectorElement: [Tuple2[Tuple2[A, Option[B]], Option[C]]]
...
}
}
Is there any proper way to prevent Seq[Nothing] (changes in query)?
Or if the query result type is fine, could you please share solution how to map it to the case classes above?
Right now I'm using next solution, but I suppose that some part of code can be optimized (e.g. groupBy replacing with something else).
execute(query).mapTo[Vector[((A, Option[B]), Option[C])]]
.flatMap { insideFuture =>
insideFuture.groupBy(_._1._1).mapValues { values =>
//scala groupBy losts ordering
val orderedB = values.groupBy(_._1._2).toSeq.sortBy(_._1.map(_.id)).toMap
orderedB.mapValues(_.map(_._2))
}.headOption match {
case Some(data) => Future.successful {
data._1.copy(bList = data._2.map {
case (Some(bElement), optionCElements) =>
bElement.copy(cList = optionCElements.toList.flatten)
case _ =>
throw new Exception("Invalid query result. Unable to find B elements")
}.toList)
}
case None => Future.failed(new Exception("Unable to find A with next id " + incomigAId))
}
}
}
I have 2 immutable case classes A(source, key, value) and B(source, key, value)
I want to add A over B in such a way when 'source' and 'key' doesn't exist, to be added from A to the B and when 'source' and 'key' exist to replace the value from B with the one from A. The same way 'merge_array' function from php works on a multidimensional array.
I tried with 'A.union(B).groupBy(.key)' and then 'groupBy(.source)' and get the 1st value. But then I realized that I can never be sure that first value will always be the value of A.
I'm quite new to scala and I really ran out of ideas how I could do this from a functional immutable point of view.
Anyone has any idea how I could do this?
Thank you
Edit:
case class TranslationValue(source: String, key: String, value: String)
def main(args:Array[String]):Unit = {
println(merge(data1.toSet, data2.toSet))
}
def merge(a: Set[TranslationValue], b: Set[TranslationValue]) = {
a.union(b).groupBy(_.key).flatMap{ case (s, v) =>
v.groupBy(_.source).flatMap{case (s1, v1) => {
for (res <- 0 to 0) yield v1.head
}
}
}
}
Example
data1 has this data
Set(
TranslationValue(messages,No,No),
TranslationValue(messages,OrdRef,Order Reference),
TranslationValue(messages,OrdId,Order Id)
)
data2 has this data
Set(
TranslationValue(messages,No,No),
TranslationValue(messages,OrdRef,OrderRef)
TranslationValue(messages,Name,Name)
)
putting data1 over data2 I want to obtain
List(
TranslationValue(messages,No,No),
TranslationValue(messages,OrdRef,Order Reference),
TranslationValue(messages,OrdId,Order Id)
TranslationValue(messages,Name,Name)
)
I know that what I do can be done better, but like I said, I'm learning :)
you can group in one go:
def merge(a: Seq[TranslationValue], b: Seq[TranslationValue]) = {
a.union(b).groupBy(t=>(t.key,t.source)).map(c=>c._2.head)
}
i think you could also override the equals method for TranslationValue so that two translation values are equal when source and key are the same(the hashcode method has also to be overridden). Then a.union(b) would be enough.
edit:
It seems Set doesnt guarantee order of items(Scala: Can I rely on the order of items in a Set?), but a seq should.
I am facing a major issue with my design at this juncture. My method is trying to accomplish the follows:
Insert the passed in object into the database.
Get the autoincremented id from the insert and use it to call webservice1 along with the object.
Get the result from webservice1 and call webservice2 with the original object and some response from webservice1.
Combine the results from webservice1 and 2 and write it into the database.
Get the resulting autoincremented id from the last insert and call webservice3 with the original object that would eventually result into the success or failure of the operation.
I want to design this in a flexible manner since the requirements are in a flux and I do not want to keep on modifying my logic based on any changing. I do realize some amount of change is inevitable but I would like to minimize the damage and respect the open-closed principle.
My initial take was as follows:
def complexOperation(someObject:T) =
dbService.insertIntoDb(someObject) match {
case Left(e:Exception) => Left(e)
case Right(id:Int) => webService.callWebService1(id,someObject) match {
case Left(e:Exception) => Left(e)
case Right(r:SomeResponse1) => webService.callWebservice2(r,someObject) match {
case Left(e:Exception) => webService.rollbackService1();Left(e)
case Right(context:ResponseContext) => dbService.insertContextIntoDb(context) match {
case Left(e:Exception) => Left(e)
case Right(id:Int) => webService.callWebservice3(id,someObject) match {
case Left(e:Exception) => webService.rollbackService3();Left(e)
case Right(r:Response) => Right(r)
}
}
}
}
As you can see, this is a tangled mess. I can neither unit test it, nor extend it nor very easily debug it if things spiral out of control. This code serves its purpose but it will be great to get some ideas on how I should refactor it to make the lives of the people who inherit my code a little more easier.
Thanks
Have a look at scala.util.Try. It's available in Scala 2.10, which may or may not be available to you as an option, but the idea of it is perfect for your scenario.
What you have in your code example is what I like calling the "pyramid" of nesting. The best solution to this is to use flat-mapping wherever you can. But obviously that's an issue when you have stuff like Either[Exception, Result] at every step. That's where Try comes in. Try[T] is essentially a replacement for Either[Exception, T], and it comes with all of the flatMap-ing goodness that you need.
Assuming you can either change the return type of those webService calls, or provide some implicit conversion from Either[Exception, Result] to Try[Result], your code block would become something more like...
for {
id <- dbService.insertIntoDb(someObject)
r <- webService.callWebService1(id,someObject)
context <- webService.callWebservice2(r,someObject)
id2 <- dbService.insertContextIntoDb(context)
response <- webService.callWebservice3(id,someObject).recoverWith {
case e: Exception => webService.rollbackService3(); Failure(e)
}
} yield response
Lift has a similar mechanism in net.liftweb.common.Box. It's like Option, but with a container for Exceptions too.
edit: It looks like you can use the left or right method of an Either, and it will let you use flatMap-ing almost exactly the way I described with Try. The only difference is that the end result is an Either[Exception, Result] instead of a Try[Result]. Check out LeftProjection for details/examples.
You can use for comprehension to reduce the noise in the code.
#Dylan had the right idea above. Let me see if I can help translate what you want to do into idiomatic Scala 2.9.1 code.
This version doesn't attempt any rollbacks:
// 1: No rollbacks, just returns the first exception in Left
def complexOperation1(someObject:T): Either[Exception, Response] = {
for {
id <- dbService.insertIntoDb(someObject).right
r <- webService.callWebService1(id, someObject).right
context <- webService.callWebservice2(idResp, someObject).right
id2 <- dbService.insertContextIntoDb(context).right
response <- webService.callWebservice3(id,someObject).right
} yield response
}
Now, let's try to do the rollbacks exactly as you had them above:
// 2: Rolls back all web services and returns first exception in Left
def complexOperation1(someObject:T): Either[Exception, Response] = {
for {
id <- dbService.insertIntoDb(someObject).right
r <- webService.callWebService1(id, someObject).right
context <- webService.callWebservice2(idResp, someObject).left.map { e =>
webService.rollbackService1()
e
}.right
id2 <- dbService.insertContextIntoDb(context).right
response <- webService.callWebservice3(id,someObject).left.map { e =>
webService.rollbackService3()
e
}.right
} yield response
}
If you define a function which does the effect (the rollback) on the left, it get's a little cleaner and easier to test, for example:
// 3: Factor out the side-effect of doing the follbacks on Left
def rollbackIfLeft[T](f: => Either[Exception, T], r: => Unit): Either[Exception, T] = {
val result = f
result.left.foreach(_ => r) // do the rollback if any exception occured
result
}
def complexOperation1(someObject:T): Either[Exception, Response] = {
for {
id <- dbService.insertIntoDb(someObject).right
r <- webService.callWebService1(id, someObject).right
context <- rollbackIfLeft(webService.callWebservice2(idResp, someObject),
webService.rollbackService1()).right
id2 <- dbService.insertContextIntoDb(context).right
response <- rollbackIfLeft(webService.callWebservice3(id,someObject),
webService.rollbackService3()).right
} yield response
}
You can try out rollbackIfLeft in the scala REPL to get a sense of it:
scala> rollbackIfLeft(Right(42), println("hey"))
res28: Either[Exception,Int] = Right(42)
scala> rollbackIfLeft(Left(new RuntimeException), println("ERROR!"))
ERROR!
res29: Either[Exception,Nothing] = Left(java.lang.RuntimeException)
Hope this helps!