Skip to content

Commit 77c556c

Browse files
authored
Merge pull request #149 from mockito/reordered-default-args
Idiomatic API supports re-ordered default args and path dependent default args
2 parents 952f78d + 07388b1 commit 77c556c

File tree

6 files changed

+271
-161
lines changed

6 files changed

+271
-161
lines changed

Diff for: macro/src/main/scala/org/mockito/DoSomethingMacro.scala

+58-60
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,8 @@ object DoSomethingMacro {
1111

1212
val r = c.Expr[S] {
1313
c.macroApplication match {
14-
case q"$_.DoSomethingOps[$_]($v).willBe($_.returned).by[$_]($obj.$method[..$targs](...$args))($_)" =>
15-
val newArgs = args.map(a => transformArgs(c)(a))
16-
q"_root_.org.mockito.MockitoSugar.doReturn($v).when($obj).$method[..$targs](...$newArgs)"
17-
18-
case q"$_.DoSomethingOps[$_]($v).willBe($_.returned).by[$_]($obj.$method[..$targs])($_)" =>
19-
q"_root_.org.mockito.MockitoSugar.doReturn($v).when($obj).$method[..$targs]"
14+
case q"$_.DoSomethingOps[$_]($v).willBe($_.returned).by[$_]($invocation)($_)" =>
15+
transformInvocation(c)(invocation, q"_root_.org.mockito.MockitoSugar.doReturn($v)")
2016

2117
case o => throw new Exception(s"Couldn't recognize ${show(o)}")
2218
}
@@ -30,12 +26,8 @@ object DoSomethingMacro {
3026

3127
val r = c.Expr[S] {
3228
c.macroApplication match {
33-
case q"$_.$cls[$_]($v).willBe($_.returnedF).by[$f, $s]($obj.$method[..$targs](...$args))(..$_)" if cls.toString.startsWith("DoSomethingOps") =>
34-
val newArgs = args.map(a => transformArgs(c)(a))
35-
q"_root_.org.mockito.${packageName(c)(cls)}.${className(c)(cls, "Mockito")}.doReturnF[$f, $s]($v)($F).when($obj).$method[..$targs](...$newArgs)"
36-
37-
case q"$_.$cls[$_]($v).willBe($_.returnedF).by[$f, $s]($obj.$method[..$targs])(..$_)" if cls.toString.startsWith("DoSomethingOps") =>
38-
q"_root_.org.mockito.${packageName(c)(cls)}.${className(c)(cls, "Mockito")}.doReturnF[$f, $s]($v)($F).when($obj).$method[..$targs]"
29+
case q"$_.$cls[$_]($v).willBe($_.returnedF).by[$f, $s]($invocation)(..$_)" if cls.toString.startsWith("DoSomethingOps") =>
30+
transformInvocation(c)(invocation, q"_root_.org.mockito.${packageName(c)(cls)}.${className(c)(cls, "Mockito")}.doReturnF[$f, $s]($v)")
3931

4032
case o => throw new Exception(s"Couldn't recognize ${show(o)}")
4133
}
@@ -49,12 +41,8 @@ object DoSomethingMacro {
4941

5042
val r = c.Expr[S] {
5143
c.macroApplication match {
52-
case q"$_.$cls[$_]($v).willBe($_.returnedFG).by[$f, $g, $s]($obj.$method[..$targs](...$args))(..$_)" if cls.toString.startsWith("DoSomethingOps") =>
53-
val newArgs = args.map(a => transformArgs(c)(a))
54-
q"_root_.org.mockito.${packageName(c)(cls)}.${className(c)(cls, "Mockito")}.doReturnFG[$f, $g, $s]($v)($F, $G).when($obj).$method[..$targs](...$newArgs)"
55-
56-
case q"$_.$cls[$_]($v).willBe($_.returnedFG).by[$f, $g, $s]($obj.$method[..$targs])(..$_)" if cls.toString.startsWith("DoSomethingOps") =>
57-
q"_root_.org.mockito.${packageName(c)(cls)}.${className(c)(cls, "Mockito")}.doReturnFG[$f, $g, $s]($v)($F, $G).when($obj).$method[..$targs]"
44+
case q"$_.$cls[$_]($v).willBe($_.returnedFG).by[$f, $g, $s]($invocation)(..$_)" if cls.toString.startsWith("DoSomethingOps") =>
45+
transformInvocation(c)(invocation, q"_root_.org.mockito.${packageName(c)(cls)}.${className(c)(cls, "Mockito")}.doReturnFG[$f, $g, $s]($v)")
5846

5947
case o => throw new Exception(s"Couldn't recognize ${show(o)}")
6048
}
@@ -68,12 +56,8 @@ object DoSomethingMacro {
6856

6957
val r = c.Expr[S] {
7058
c.macroApplication match {
71-
case q"$_.$cls[..$_]($v).willBe($_.answered).by[$_]($obj.$method[..$targs](...$args))($_)" if cls.toString.startsWith("DoSomethingOps") =>
72-
val newArgs = args.map(a => transformArgs(c)(a))
73-
q"_root_.org.mockito.MockitoSugar.doAnswer($v).when($obj).$method[..$targs](...$newArgs)"
74-
75-
case q"$_.$cls[..$_]($v).willBe($_.answered).by[$_]($obj.$method[..$targs])($_)" if cls.toString.startsWith("DoSomethingOps") =>
76-
q"_root_.org.mockito.MockitoSugar.doAnswer($v).when($obj).$method[..$targs]"
59+
case q"$_.$cls[..$_]($v).willBe($_.answered).by[$_]($invocation)($_)" if cls.toString.startsWith("DoSomethingOps") =>
60+
transformInvocation(c)(invocation, q"_root_.org.mockito.MockitoSugar.doAnswer($v)")
7761

7862
case o => throw new Exception(s"Couldn't recognize ${show(o)}")
7963
}
@@ -87,12 +71,8 @@ object DoSomethingMacro {
8771

8872
val r = c.Expr[S] {
8973
c.macroApplication match {
90-
case q"$_.$cls[..$ftargs]($v).willBe($_.answeredF).by[$f, $_]($obj.$method[..$targs](...$args))(..$_)" if cls.toString.startsWith("DoSomethingOps") =>
91-
val newArgs = args.map(a => transformArgs(c)(a))
92-
q"_root_.org.mockito.${packageName(c)(cls)}.${className(c)(cls, "Mockito")}.doAnswerF[$f, ..$ftargs]($v).when($obj).$method[..$targs](...$newArgs)"
93-
94-
case q"$_.$cls[..$ftargs]($v).willBe($_.answeredF).by[$f, $_]($obj.$method[..$targs])(..$_)" if cls.toString.startsWith("DoSomethingOps") =>
95-
q"_root_.org.mockito.${packageName(c)(cls)}.${className(c)(cls, "Mockito")}.doAnswerF[$f, ..$ftargs]($v).when($obj).$method[..$targs]"
74+
case q"$_.$cls[..$ftargs]($v).willBe($_.answeredF).by[$f, $_]($invocation)(..$_)" if cls.toString.startsWith("DoSomethingOps") =>
75+
transformInvocation(c)(invocation, q"_root_.org.mockito.${packageName(c)(cls)}.${className(c)(cls, "Mockito")}.doAnswerF[$f, ..$ftargs]($v)")
9676

9777
case o => throw new Exception(s"Couldn't recognize ${show(o)}")
9878
}
@@ -106,12 +86,8 @@ object DoSomethingMacro {
10686

10787
val r = c.Expr[S] {
10888
c.macroApplication match {
109-
case q"$_.$cls[..$ftargs]($v).willBe($_.answeredFG).by[$f, $g, $_]($obj.$method[..$targs](...$args))(..$_)" if cls.toString.startsWith("DoSomethingOps") =>
110-
val newArgs = args.map(a => transformArgs(c)(a))
111-
q"_root_.org.mockito.${packageName(c)(cls)}.${className(c)(cls, "Mockito")}.doAnswerFG[$f, $g, ..$ftargs]($v).when($obj).$method[..$targs](...$newArgs)"
112-
113-
case q"$_.$cls[..$ftargs]($v).willBe($_.answeredFG).by[$f, $g, $_]($obj.$method[..$targs])(..$_)" if cls.toString.startsWith("DoSomethingOps") =>
114-
q"_root_.org.mockito.${packageName(c)(cls)}.${className(c)(cls, "Mockito")}.doAnswerFG[$f, $g, ..$ftargs]($v).when($obj).$method[..$targs]"
89+
case q"$_.$cls[..$ftargs]($v).willBe($_.answeredFG).by[$f, $g, $_]($invocation)(..$_)" if cls.toString.startsWith("DoSomethingOps") =>
90+
transformInvocation(c)(invocation, q"_root_.org.mockito.${packageName(c)(cls)}.${className(c)(cls, "Mockito")}.doAnswerFG[$f, $g, ..$ftargs]($v)")
11591

11692
case o => throw new Exception(s"Couldn't recognize answeredFG ${show(o)}")
11793
}
@@ -125,12 +101,8 @@ object DoSomethingMacro {
125101

126102
val r = c.Expr[T] {
127103
c.macroApplication match {
128-
case q"$_.ThrowSomethingOps[$_]($v).willBe($_.thrown).by[$_]($obj.$method[..$targs](...$args))($_)" =>
129-
val newArgs = args.map(a => transformArgs(c)(a))
130-
q"_root_.org.mockito.MockitoSugar.doThrow($v).when($obj).$method[..$targs](...$newArgs)"
131-
132-
case q"$_.ThrowSomethingOps[$_]($v).willBe($_.thrown).by[$_]($obj.$method[..$targs])($_)" =>
133-
q"_root_.org.mockito.MockitoSugar.doThrow($v).when($obj).$method[..$targs]"
104+
case q"$_.ThrowSomethingOps[$_]($v).willBe($_.thrown).by[$_]($invocation)($_)" =>
105+
transformInvocation(c)(invocation, q"_root_.org.mockito.MockitoSugar.doThrow($v)")
134106

135107
case o => throw new Exception(s"Couldn't recognize ${show(o)}")
136108
}
@@ -144,12 +116,8 @@ object DoSomethingMacro {
144116

145117
val r = c.Expr[T] {
146118
c.macroApplication match {
147-
case q"$_.$cls[$e]($v).willBe($_.raised).by[$f, $t]($obj.$method[..$targs](...$args))(..$_)" if cls.toString.startsWith("DoSomethingOps") =>
148-
val newArgs = args.map(a => transformArgs(c)(a))
149-
q"_root_.org.mockito.${packageName(c)(cls)}.${className(c)(cls, "Mockito")}.doFailWith[$f, $e, $t]($v)($F).when($obj).$method[..$targs](...$newArgs)"
150-
151-
case q"$_.$cls[$e]($v).willBe($_.raised).by[$f, $t]($obj.$method[..$targs])(..$_)" if cls.toString.startsWith("DoSomethingOps") =>
152-
q"_root_.org.mockito.${packageName(c)(cls)}.${className(c)(cls, "Mockito")}.doFailWith[$f, $e, $t]($v)($F).when($obj).$method[..$targs]"
119+
case q"$_.$cls[$e]($v).willBe($_.raised).by[$f, $t]($invocation)(..$_)" if cls.toString.startsWith("DoSomethingOps") =>
120+
transformInvocation(c)(invocation, q"_root_.org.mockito.${packageName(c)(cls)}.${className(c)(cls, "Mockito")}.doFailWith[$f, $e, $t]($v)")
153121

154122
case o => throw new Exception(s"Couldn't recognize ${show(o)}")
155123
}
@@ -163,12 +131,8 @@ object DoSomethingMacro {
163131

164132
val r = c.Expr[T] {
165133
c.macroApplication match {
166-
case q"$_.$cls[$e]($v).willBe($_.raisedG).by[$f, $g, $t]($obj.$method[..$targs](...$args))(..$_)" if cls.toString.startsWith("DoSomethingOps") =>
167-
val newArgs = args.map(a => transformArgs(c)(a))
168-
q"_root_.org.mockito.${packageName(c)(cls)}.${className(c)(cls, "Mockito")}.doFailWithG[$f, $g, $e, $t]($v)($F, $G).when($obj).$method[..$targs](...$newArgs)"
169-
170-
case q"$_.$cls[$e]($v).willBe($_.raisedG).by[$f, $g, $t]($obj.$method[..$targs])(..$_)" if cls.toString.startsWith("DoSomethingOps") =>
171-
q"_root_.org.mockito.${packageName(c)(cls)}.${className(c)(cls, "Mockito")}.doFailWithG[$f, $g, $e, $t]($v)($F, $G).when($obj).$method[..$targs]"
134+
case q"$_.$cls[$e]($v).willBe($_.raisedG).by[$f, $g, $t]($invocation)(..$_)" if cls.toString.startsWith("DoSomethingOps") =>
135+
transformInvocation(c)(invocation, q"_root_.org.mockito.${packageName(c)(cls)}.${className(c)(cls, "Mockito")}.doFailWithG[$f, $g, $e, $t]($v)")
172136

173137
case o => throw new Exception(s"Couldn't recognize ${show(o)}")
174138
}
@@ -182,17 +146,51 @@ object DoSomethingMacro {
182146

183147
val r = c.Expr[T] {
184148
c.macroApplication match {
185-
case q"$_.theRealMethod.willBe($_.called).by[$_]($obj.$method[..$targs](...$args))" =>
186-
val newArgs = args.map(a => transformArgs(c)(a))
187-
q"_root_.org.mockito.MockitoSugar.doCallRealMethod.when($obj).$method[..$targs](...$newArgs)"
188-
189-
case q"$_.theRealMethod.willBe($_.called).by[$_]($obj.$method[..$targs])" =>
190-
q"_root_.org.mockito.MockitoSugar.doCallRealMethod.when($obj).$method[..$targs]"
149+
case q"$_.theRealMethod.willBe($_.called).by[$_]($invocation)" =>
150+
transformInvocation(c)(invocation, q"_root_.org.mockito.MockitoSugar.doCallRealMethod")
191151

192152
case o => throw new Exception(s"Couldn't recognize ${show(o)}")
193153
}
194154
}
195155
if (c.settings.contains("mockito-print-do-something")) println(show(r.tree))
196156
r
197157
}
158+
159+
private def transformInvocation(c: blackbox.Context)(invocation: c.Tree, action: c.Tree): c.Tree = {
160+
import c.universe._
161+
162+
val pf: PartialFunction[c.Tree, c.Tree] = {
163+
case q"$obj.$method[..$targs](...$args)" =>
164+
val newArgs = args.map(a => transformArgs(c)(a))
165+
q"$action.when($obj).$method[..$targs](...$newArgs)"
166+
case q"$obj.$method[..$targs]" =>
167+
q"$action.when($obj).$method[..$targs]"
168+
}
169+
170+
if (pf.isDefinedAt(invocation))
171+
pf(invocation)
172+
else if (pf.isDefinedAt(invocation.children.last)) {
173+
val values = invocation.children
174+
.dropRight(1)
175+
.collect {
176+
case q"$_ val $name:$_ = $value" => name.toString -> value.asInstanceOf[c.Tree]
177+
}
178+
.toMap
179+
180+
val nonMatchers = invocation.children.dropRight(1).collect {
181+
case t @ q"$_ val $_:$_ = $value" if !isMatcher(c)(value) => t
182+
}
183+
184+
invocation.children.last match {
185+
case q"$obj.$method[..$targs](...$args)" =>
186+
val newArgs = args.map { a =>
187+
transformArgs(c)(a).map {
188+
case p if show(p).startsWith("x$") => transformArg(c)(values(p.toString))
189+
case other => other
190+
}
191+
}
192+
q"..$nonMatchers; $action.when($obj).$method[..$targs](...$newArgs)"
193+
}
194+
} else throw new Exception(s"Couldn't recognize invocation ${show(invocation)}")
195+
}
198196
}

Diff for: macro/src/main/scala/org/mockito/Utils.scala

+3-2
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,9 @@ object Utils {
8484
if (isMatcher(c)(arg)) arg
8585
else
8686
arg match {
87-
case q"$a: _*" => q"_root_.org.mockito.matchers.DefaultMatcher($a): _*"
88-
case q"$a" => q"_root_.org.mockito.matchers.DefaultMatcher($a)"
87+
case a if a.toString.startsWith("x$") => a
88+
case q"$a: _*" => q"_root_.org.mockito.matchers.DefaultMatcher($a): _*"
89+
case q"$a" => q"_root_.org.mockito.matchers.DefaultMatcher($a)"
8990
}
9091
}
9192

Diff for: macro/src/main/scala/org/mockito/VerifyMacro.scala

+63-33
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,74 @@ object Called {
1111

1212
object VerifyMacro {
1313

14+
def wasMacro[T: c.WeakTypeTag, R](c: blackbox.Context)(called: c.Tree)(order: c.Expr[VerifyOrder]): c.Expr[R] = {
15+
import c.universe._
16+
17+
val r = c.Expr[R](transformVerification(c)(c.macroApplication))
18+
if (c.settings.contains("mockito-print-verify")) println(show(r.tree))
19+
r
20+
}
21+
22+
def wasNeverCalledAgainMacro[T: c.WeakTypeTag, R](c: blackbox.Context)(called: c.Tree)($ev: c.Tree): c.Expr[R] = {
23+
import c.universe._
24+
25+
val r = c.Expr[R](transformVerification(c)(c.macroApplication))
26+
if (c.settings.contains("mockito-print-verify")) println(show(r.tree))
27+
r
28+
}
29+
1430
object Never extends ScalaVerificationMode {
1531
override def verificationMode: VerificationMode = Mockito.never
1632
}
1733

18-
def transformVerification[T: c.WeakTypeTag, R](c: blackbox.Context)(called: c.Tree): c.Tree = {
34+
object Once extends ScalaVerificationMode {
35+
override def verificationMode: VerificationMode = Mockito.times(1)
36+
}
37+
38+
private def transformInvocation(c: blackbox.Context)(invocation: c.Tree, order: c.Tree, times: c.Tree): c.Tree = {
1939
import c.universe._
2040

21-
called match {
22-
case q"$_.VerifyingOps[$_]($obj.$method[..$targs](...$args)).was($_.called)($order)" =>
41+
val pf: PartialFunction[c.Tree, c.Tree] = {
42+
case q"$obj.$method[..$targs](...$args)" =>
2343
val newArgs = args.map(a => transformArgs(c)(a))
24-
q"verification($order.verify($obj).$method[..$targs](...$newArgs))"
44+
q"verification($order.verifyWithMode($obj, $times).$method[..$targs](...$newArgs))"
45+
case q"$obj.$method[..$targs]" =>
46+
q"verification($order.verifyWithMode($obj, $times).$method[..$targs])"
47+
}
48+
49+
if (pf.isDefinedAt(invocation))
50+
pf(invocation)
51+
else if (pf.isDefinedAt(invocation.children.last)) {
52+
val values = invocation.children
53+
.dropRight(1)
54+
.collect {
55+
case q"$_ val $name:$_ = $value" => name.toString -> value.asInstanceOf[c.Tree]
56+
}
57+
.toMap
58+
59+
val nonMatchers = invocation.children.dropRight(1).collect {
60+
case t @ q"$_ val $_:$_ = $value" if !isMatcher(c)(value) => t
61+
}
62+
63+
invocation.children.last match {
64+
case q"$obj.$method[..$targs](...$args)" =>
65+
val newArgs = args.map { a =>
66+
transformArgs(c)(a).map {
67+
case p if show(p).startsWith("x$") => transformArg(c)(values(p.toString))
68+
case other => other
69+
}
70+
}
71+
q"..$nonMatchers; verification($order.verifyWithMode($obj, $times).$method[..$targs](...$newArgs))"
72+
}
73+
} else throw new Exception(s"Couldn't recognize invocation ${show(invocation)}")
74+
}
2575

26-
case q"$_.VerifyingOps[$_]($obj.$method[..$targs]).was($_.called)($order)" =>
27-
q"verification($order.verify($obj).$method[..$targs])"
76+
def transformVerification[T: c.WeakTypeTag, R](c: blackbox.Context)(called: c.Tree): c.Tree = {
77+
import c.universe._
78+
79+
called match {
80+
case q"$_.VerifyingOps[$_]($invocation).was($_.called)($order)" =>
81+
transformInvocation(c)(invocation, order, q"_root_.org.mockito.VerifyMacro.Once")
2882

2983
case q"$_.VerifyingOps[$_]($_.this.$obj).wasNever($called)($_)" =>
3084
called match {
@@ -35,11 +89,7 @@ object VerifyMacro {
3589
}
3690

3791
case q"$_.VerifyingOps[$_]($obj.$method[..$targs](...$args)).wasNever($_.called)($order)" =>
38-
val newArgs = args.map(a => transformArgs(c)(a))
39-
q"verification($order.verifyWithMode($obj, _root_.org.mockito.VerifyMacro.Never).$method[..$targs](...$newArgs))"
40-
41-
case q"$_.VerifyingOps[$_]($obj.$method[..$targs]).wasNever($_.called)($order)" =>
42-
q"verification($order.verifyWithMode($obj, _root_.org.mockito.VerifyMacro.Never).$method[..$targs])"
92+
transformInvocation(c)(q"$obj.$method[..$targs](...$args)", order, q"_root_.org.mockito.VerifyMacro.Never")
4393

4494
case q"$_.VerifyingOps[$_]($obj).wasNever($called)($_)" =>
4595
called match {
@@ -49,32 +99,12 @@ object VerifyMacro {
4999
q"verification(_root_.org.mockito.MockitoSugar.verifyNoMoreInteractions(_root_.org.mockito.MockitoSugar.ignoreStubs($obj): _*))"
50100
}
51101

52-
case q"$_.VerifyingOps[$_]($obj.$method[..$targs](...$args)).wasCalled($times)($order)" =>
53-
val newArgs = args.map(a => transformArgs(c)(a))
54-
q"verification($order.verifyWithMode($obj, $times).$method[..$targs](...$newArgs))"
55-
56-
case q"$_.VerifyingOps[$_]($obj.$method[..$targs]).wasCalled($times)($order)" =>
57-
q"verification($order.verifyWithMode($obj, $times).$method[..$targs])"
102+
case q"$_.VerifyingOps[$_]($invocation).wasCalled($times)($order)" =>
103+
transformInvocation(c)(invocation, order, times)
58104

59105
case o => throw new Exception(s"VerifyMacro: Couldn't recognize ${show(o)}")
60106
}
61107
}
62-
63-
def wasMacro[T: c.WeakTypeTag, R](c: blackbox.Context)(called: c.Tree)(order: c.Expr[VerifyOrder]): c.Expr[R] = {
64-
import c.universe._
65-
66-
val r = c.Expr[R](transformVerification(c)(c.macroApplication))
67-
if (c.settings.contains("mockito-print-verify")) println(show(r.tree))
68-
r
69-
}
70-
71-
def wasNeverCalledAgainMacro[T: c.WeakTypeTag, R](c: blackbox.Context)(called: c.Tree)($ev: c.Tree): c.Expr[R] = {
72-
import c.universe._
73-
74-
val r = c.Expr[R](transformVerification(c)(c.macroApplication))
75-
if (c.settings.contains("mockito-print-verify")) println(show(r.tree))
76-
r
77-
}
78108
}
79109

80110
trait ScalaVerificationMode {

0 commit comments

Comments
 (0)