RSpec: expect array of hashes in class_double recieve - ruby-on-rails-4

I want to test with RSpec a function my_test. The function calls another class's class method MyHelper.func in rails 4.
I used mock to illustrate func in class MyHelper, and I want to match the argument that func receives with some const values.
I used
expect(<double>).to receive(func).with(arguments)
But one of the const arguments is a hash with more than 2 items. When I test my
function, RSpec throws an error:
received :func with unexpected arguments.
expected: [{"1"=>33.33},{"2"=>33.33},{"3"=>33.33}]
got: [{"2"=>33.33},{"1"=>33.33},{"3"=>33.33}]
Is there a way to match between the two arrays?
The code:
my_hash = [{"1"=>33.33},{"2"=>33.33},{"3"=>33.33}]
notifier = class_double("MyHelper").
as_stubbed_const(:transfer_nested_constant => true)
expect(notifier).to receive(:func).with(my_hash)

This is a bit tricky since you are comparing two things that are not equal when using ==
let(:expected) { [{"1"=>33.33},{"2"=>33.33},{"3"=>33.33}] }
let(:actual) { [{"2"=>33.33},{"1"=>33.33},{"3"=>33.33}] }
expect(actual).to eq(expected) # fails
However, you can define a custom matcher and use it to compare the arguments:
RSpec::Matchers.define :sorted_array_match do |expected|
match do |actual|
expected_hash = expected.inject({}) {|m,(k,v)| m.merge!(k=>v)}
actual_hash = actual.inject({}) {|m,(k,v)| m.merge!(k=>v)}
actual_hash == expected_hash
end
end
it "should work" do
expect(notifier).to receive(:func).with(sorted_array_match(expected))
notifier.func(actual)
end
Note that this converts the array argument into a hash, so it assumes the arguments are arrays containing hashes with different keys. You might need to alter it to fit the actual data.
More info in the RSpec docs.

Related

assertEquals fails for Error implementation but pass for Success one

I have these sealed interface
sealed interface Result<out T> {
data class Success<T>(val data: T) : Result<T>
data class Error(val exception: Throwable? = null) : Result<Nothing>
}
when i tried to assertEquals the Success one, it pass. But when it comes to Error one, it will fail even though the content is identical. Here is simple example:
#Test
fun testSucess() = runTest {
whenever(repository.login("email", "password"))
.thenReturn(someValue)
val expected = Result.Success(data = someValue)
val actual = loginUseCase(LoginRequest("email", "password"))
verify(repository).login("email", "password")
assertEquals(expected, actual) // this will pass
}
#Test
fun testError() = runTest {
val exception = RuntimeException("HTTP Error")
whenever(repository.login("", ""))
.thenThrow(exception)
val expected = Result.Error(exception = exception)
val actual = loginUseCase(LoginRequest("", ""))
verify(repository).login("", "")
assertEquals(expected, actual) // this will fail
assertEquals(expected.toString(), actual.toString()) // this will pass
}
What is causing this and what is possible solution to this? I have read some info that it needs equals() to be overriden, but i still confused as to why it only happens in Error case only and how to properly override the equals method.
Data classes in Kotlin have an implicitly generated equals function automatically derived from all their properties.
The problem you are facing is probably due to the fact that the type of your someValue has a proper equals function, so the equals works for your Success and its property value. But Throwable does not have an equals function which means that two Throwables are only equal if they are the same instance, which is obviously not the case for expected and actual in your test assertion. I can only guess that in loginUseCase, the exception is wrapped inside another exception, or a new exception is created based on the one thrown by the repository?
Kotlin already has a built-in Result type, and I strongly recommend using that one instead of defining your own.
Nonetheless, if you use the built-in type, you will probably face the same problem, since the equals check still fails for the different exception instances.
There are several ways to solve that:
Define your own exception type and override the equals function to return true if they are both of the same type and have the same message.
Check for expected is Error (or with the default Result type that expected.isFailure), and then check that the messages are the same.
Make sure that loginUseCase throws exactly the same exception instance as is thrown by the repository.

Akka Streams Graph DSL notation

I used graph dsl to create some stream processing jobs based on some example code I saw. Everything runs great, I am just having trouble understanding the notation: (updated for 2.4)
def elements: Source[Foos] = ...
def logEveryNSink = // a sink that logs
def cleaner: Flow[Foos, Bars, Unit] = ...
def boolChecker(bar: Bar)(implicit ex: ExecutionContext): Future[Boolean] = ...
val mySink = Sink.foreach[Boolean](println(_))
val lastly = Flow[Bars].mapAsync(2)(x => boolChecker(x).toMat(mySink)(Keep.right)
val materialized = RunnableGraph.fromGraph(
GraphDSL.create(lastly) { implicit builder =>
baz => {
import GraphDSL.Implicits._
val broadcast1 = builder.add(Broadcast[Foos](2))
val broadcast2 = builder.add(Broadcast[Bars](2))
elements ~> broadcast1 ~> logEveryNSink(1)
broadcast1 ~> cleaner ~> broadcast2 ~> baz
~> broadcast2 ~> logEveryNSink(1)
ClosedShape
}
}
).run()
I understand the implicit builder that is included, but Im uncertain what the baz represents in { implicit builder => baz => { .... is it just an implicit name for the entire shape?
The GraphDSL.create method is heavily overloaded to take in many variants of amounts of input shapes (including 0). If you pass in no initial shapes, then the signature of the buildBlock function arg (the body where you actually define how the graph is to be built) is as follows:
(Builder[NotUsed]) => S
So this is simply a Function1[Builder[NotUsed], S], that is, a function that takes an instance of a Builder[NotUsed] and returns a Shape instance which is the final graph. The NotUsed here is synonymous with Unit in that you are saying that by not passing in any input shares that you do not care about the materialized value of the output graph being produced.
If you do decide to pass in input shapes, then the signature of that buildBlock function changes a bit to accomadate the input shapes. In your case, you are passing in 1 input shape, so the signature of buildBlock changes to:
(Builder[Mat]) => Graph.Shape => S
Now, this is essentially a Function1[Builder[Mat], Function1[Graph.Shape, S]], or a function that takes a Builder[Mat] (where Mat is the materialized value type of the input shape) and returns a function that takes a Graph.Shape and returns an instance of S (which is a Shape).
Long story short, if you pass in shapes, then you also need to declare them as bound params on the graph building block function but as a second input function (hence the additional =>).

What is the optimal way (not using Scalaz) to type require a non-empty List?

As I am working a design model, I am torn between two different methods of indicating a parameter of type List must be nonEmpty. I began by using List[Int] with an accompanying require statement to verify the List is nonEmpty.
case class A(name: String, favoriteNumbers: List[Int]) {
require(favoriteNumbers.nonEmpty, "favoriteNumbers must not be empty")
}
I then needed to make the list optional. If the List is provided, it must be nonEmpty. I'm using using Option[List[Int]] with an accompanying require statement to verify, if the Option is nonEmpty, the list must also be nonEmpty.
case class B(name: String, favoriteNumbers: Option[List[Int]]) {
require(
favoriteNumbers.isEmpty || favoriateNumbers.get.nonEmpty
, "when defined, favoriteNumbers.get must be nonEmpty"
)
}
However, I need to use this non-empty List all over the system I am modeling. This means that my code has these same require statements duplicated everywhere. Is there a (non-ScalaZ) way to have a new type, say NeList, which is defined and behaves identically to List, with the only change being an exception is thrown when NeList attempts to be instantiated with no elements?
I tried to Google for this and couldn't find a set of search terms to hone on this area. I either got really simple List how-tos, or all sorts of references to ScalaZ's NEL (Non Empty List). So, if there is a link out there that would help with this, I would love to see it.
If you
def foo[A](x: ::[A]) = "List has length "+x.length
then you insist that the list be nonempty. But of course your lists are all typed as List, so you need a helper method to give you a nonempty list:
implicit class NonEmptyList[A](private val underlying: List[A]) {
def ifNonEmpty[B](f: ::[A] => B): Option[B] = {
underlying match {
case x: ::[A #unchecked] => Some(f(x))
case _ => None
}
}
}
Now you can safely apply the operation to get an Option out. (You could also run side-effecting functions in a foreach-like method.)
Now, this is rather non-idiomatic Scala. But it is safe at compile time (the #unchecked notwithstanding--Scala's compiler isn't quite smart enough to realize that the type parameter hasn't changed).
You could implement a non-empty list yourself with implicit conversions between List[A] and Nel[A]:
case class Nel[A](val head: A, val tail: List[A] = Nil)
implicit def list2Nel[A](list: List[A]): Nel[A] = {
require(!list.isEmpty)
Nel(list.head, list.tail)
}
implicit def nel2List[A](nel: Nel[A]): List[A] = nel.head :: nel.tail
Then you can define your functions where this is needed such that they take a Nel[A] as a parameter:
def f(l: Option[Nel[String]]) = { ... }
And call them with normal lists (assuming the implicit defs are in scope):
f(Some(List("hello", "world")) // works
f(Some(Nil)) // throws IllegalArgumentException
f(None) // works
EDIT: It should be noted that this does not provide compile time guarantees that the List[A] passed in will not be empty. If that's what you want, then get rid of the implicit def list2Nel and require clients of your function to pass in an Nel[A] explicitly, thus guaranteeing at compile time that the list is not empty.
Also, this is a very basic NonEmptyList implementation. A more complete solution is found in scalaz (granted it was specifically requested in the question that scalaz not be used): https://github.com/scalaz/scalaz/blob/series/7.2.x/core/src/main/scala/scalaz/NonEmptyList.scala

ExpressionEngine templates: pass a plugin/module's output as parameter to another plugin/module

Here's basically what I want to accomplish:
{exp:plugin1:method arg="{exp:plugin2:method}"}
I’ve tried a number of different approaches.
Approach 1:
{exp:plugin1:method arg="{exp:plugin2:method}"}
Result: Plugin1->method’s arg parameter value is the string, {exp:plugin2:method}, and it’s never parsed.
Approach 2:
My understanding of the parsing order suggests that this might have different results, but apparently it does not.
{preload_replace:replaced="{exp:plugin2:method}"}
{exp:plugin1:method arg="{replaced}"}
Result: The arg parameter has the same value as approach 1.
Approach 3:
First I define a snippet (snip), whose content is:
{exp:plugin2:method}
Then in the template:
{exp:plugin1:method arg="{snip}"}
Result: Same as approaches 1 and 2.
Approach 4:
Noting that plugins are processed in the order they appear, I have even tested simply placing an instance of {exp:plugin2:method} before the {exp:plugin1:method} call. My thinking is that I could wrap this first call in a regex replacement plugin in order to suppress output, but that it would trigger Plugin2’s parsing first.
{exp:plugin2:method}
{exp:plugin1:method arg="{exp:plugin2:method}"}
Result: Plugin1->method’s arg parameter value is the temporary hash placeholder for Plugin2->method’s output (MD5 I believe) that the Template class reserves until later.
Interesting approach. However, this can be achieved more simply like this:
{exp:plugin1:method arg="{exp:plugin2:method}" parse="inward"}
I have a workaround, but I'll wait a while to see if a better solution comes up before I accept my own answer. The workaround is to wrap plugin1 with plugin2 and replace template tags referring to its methods within the tagdata. Note that this requires a parse="inward" parameter on the plugin2 call.
In the template:
{exp:plugin2 parse="inward"}
{exp:plugin1:method arg="{someplugin2method}"}
{/exp:plugin2}
In the plugin class:
static $public_methods;
function __construct() {
// Actual construction code omitted...
if(($tagdata = $this->EE->TMPL->tagdata) !== false && trim($tagdata) !== '') {
if(!isset(self::$public_methods)) {
self::$public_methods = array();
$methods = get_class_methods($this);
foreach($methods as $method) {
if($method == get_class($this) || $method == '__construct') {
continue;
}
$reflection = new ReflectionMethod(get_class($this), $method);
if($reflection->isPublic()) {
self::$public_methods[] = $method;
}
}
self::$public_methods = implode('|', self::$public_methods);
}
$tagdata = preg_replace_callback('/\{(' . self::$public_methods . ')\}/',
array($this, 'tagdata_callback'), $tagdata);
$this->return_data = $tagdata;
}
}
private function tagdata_callback($matches) {
$method = $matches[1];
return $this->$method();
}
Caveats:
This can make for messier templates.
Maintaining a list of public methods apparently requires Reflection which is not available in PHP 4. You can, of course, maintain a list of expected methods manually.

How test SqlParameter for equality

Using NUnit and NMock2 I was not able to compare what I thought were the same SqlParameters:
SqlParameter param1 = new SqlParameter("#Id", 1);
SqlParameter param2 = new SqlParameter("#Id", 1);
Assert.IsTrue(param1.Equals(param2)); // This failed
I stumbled across this problem, when trying to test an execution of a method using NMock2
[Test]
public void UpdateComments()
{
const int arbitraryId = 1;
Comment comment = new Comment();
SqlParameter idParam = new SqlParameter("#ChangeId", arbitraryId);
Expect.Once.On(mockSqlDao).Method("ExecuteNonQuery")
.With("usp_Update_Comment", idParam);
changeDao.UpdateComment(arbitraryId, comment);
mocks.VerifyAllExpectationsHaveBeenMet();
}
I received this error:
NMock2.Internal.ExpectationException: unexpected invocation of sqlDao.ExecuteNonQuery("usp_Update_Comment", )
Expected:
1 time: sqlDao.ExecuteNonQuery(equal to "usp_Update_Comment", equal to <#ChangeId>) [called 0 times]
Questions:
How do you test with NMock2 when you
expected Parameter is SqlParameter?
How do you compare equality of two SqlParameters?
Because .Equals() is using the default implementation of Equals as far as I know (which means that a SqlParameter will only "equal" another SqlParameter if they are the same object), you will need to directly interrogate the properties of the parameter to ensure the correct data is being passed.
The Has.Property call within .With allows you to check the properties of a parameter without requiring that a parameter equals some other value. Try the following:
Expect.Once.On(mockSqlDao).Method("ExecuteNonQuery")
.With("usp_Update_Comment", Has.Property("ParameterName").EqualTo("#Id") &
Has.Property("Value").EqualTo(1));