From dfd7a8677bc7d8d6b3ddf92a464855f2464f35a7 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Wed, 21 Aug 2019 08:54:25 -0700 Subject: [PATCH] airspec: Support AirSpec.design, localDesign (#631) --- .../reflect/ReflectSurfaceFactory.scala | 6 ++- .../airframe/surface/SurfaceMacros.scala | 6 ++- .../wvlet/airframe/HigherKindTypeTest.scala | 8 ++-- .../scala/wvlet/airframe/SingletonTest.scala | 6 +-- .../scala/wvlet/airspec/TestExtension.scala | 2 +- .../main/scala/wvlet/airspec/AirSpec.scala | 20 ++++++++- .../wvlet/airspec/spi/PropertyCheck.scala | 10 ++--- airspec/src/test/scala/examples/DITest.scala | 42 +++++++++++++++++++ build.sbt | 4 +- 9 files changed, 85 insertions(+), 19 deletions(-) create mode 100644 airspec/src/test/scala/examples/DITest.scala diff --git a/airframe-surface/jvm/src/main/scala/wvlet/airframe/surface/reflect/ReflectSurfaceFactory.scala b/airframe-surface/jvm/src/main/scala/wvlet/airframe/surface/reflect/ReflectSurfaceFactory.scala index 028352bd72..ac51373e24 100644 --- a/airframe-surface/jvm/src/main/scala/wvlet/airframe/surface/reflect/ReflectSurfaceFactory.scala +++ b/airframe-surface/jvm/src/main/scala/wvlet/airframe/surface/reflect/ReflectSurfaceFactory.scala @@ -155,8 +155,12 @@ object ReflectSurfaceFactory extends LogSupport { .filter(m => isOwnedByTargetClass(m, t)) } + private def nonObject(x: ru.Symbol): Boolean = { + !x.isImplementationArtifact && !x.isSynthetic && !x.isAbstract && x.fullName != "scala.Any" && x.fullName != "java.lang.Object" + } + private def isOwnedByTargetClass(m: MethodSymbol, t: ru.Type): Boolean = { - m.owner == t.typeSymbol + m.owner == t.typeSymbol || t.baseClasses.filter(nonObject).exists(_ == m.owner) } def createMethodSurfaceOf(targetType: ru.Type): Seq[MethodSurface] = { diff --git a/airframe-surface/shared/src/main/scala/wvlet/airframe/surface/SurfaceMacros.scala b/airframe-surface/shared/src/main/scala/wvlet/airframe/surface/SurfaceMacros.scala index 89ecbd3b14..9534a517bf 100644 --- a/airframe-surface/shared/src/main/scala/wvlet/airframe/surface/SurfaceMacros.scala +++ b/airframe-surface/shared/src/main/scala/wvlet/airframe/surface/SurfaceMacros.scala @@ -80,8 +80,12 @@ private[surface] object SurfaceMacros { allMethodsOf(t).filter(m => isOwnedByTargetClass(m, t)) } + private def nonObject(x: c.Symbol): Boolean = { + !x.isImplementationArtifact && !x.isSynthetic && !x.isAbstract && x.fullName != "scala.Any" && x.fullName != "java.lang.Object" + } + private def isOwnedByTargetClass(m: MethodSymbol, t: c.Type): Boolean = { - m.owner == t.typeSymbol + m.owner == t.typeSymbol || t.baseClasses.filter(nonObject).exists(_ == m.owner) } private def createMethodCaller(t: c.Type, m: MethodSymbol, methodArgs: Seq[MethodArg]): c.Tree = { diff --git a/airframe/src/test/scala/wvlet/airframe/HigherKindTypeTest.scala b/airframe/src/test/scala/wvlet/airframe/HigherKindTypeTest.scala index b14d99cd59..f23747ae2b 100644 --- a/airframe/src/test/scala/wvlet/airframe/HigherKindTypeTest.scala +++ b/airframe/src/test/scala/wvlet/airframe/HigherKindTypeTest.scala @@ -42,22 +42,22 @@ import HigherKindTypeTest._ class HigherKindTypeTest extends AirSpec { scalaJsSupport - val design = + val d = newSilentDesign .bind[HolderInterpreted].toInstance(interpreted) .bind[Holder[Task]].toInstance(interpreted2) .bind[Holder[MyFuture]].toInstance(interpreted3) def `support higher kind types`: Unit = { - design.build[HolderInterpreted] { repo => + d.build[HolderInterpreted] { repo => repo.hello shouldBe "new interpretation" } - design.build[Holder[Task]] { repo => + d.build[Holder[Task]] { repo => repo.hello shouldBe "another interpretation" } - design.build[Holder[MyFuture]] { repo => + d.build[Holder[MyFuture]] { repo => repo.hello shouldBe "third interpretation" } } diff --git a/airframe/src/test/scala/wvlet/airframe/SingletonTest.scala b/airframe/src/test/scala/wvlet/airframe/SingletonTest.scala index d95a62fdb8..fec41b42de 100644 --- a/airframe/src/test/scala/wvlet/airframe/SingletonTest.scala +++ b/airframe/src/test/scala/wvlet/airframe/SingletonTest.scala @@ -69,12 +69,12 @@ object SingletonTest { class SingletonTest extends AirSpec { scalaJsSupport - val design = + val d = newDesign .bind[TraitCounter].toInstance(new AtomicInteger(0)) def `bind singleton with bind[X]` : Unit = { - val session = design.newSession + val session = d.newSession val a = session.build[A] val b = session.build[B] @@ -84,7 +84,7 @@ class SingletonTest extends AirSpec { } def `bind singleton with bind[X] as a service`: Unit = { - val session = design.newSession + val session = d.newSession val u1 = session.build[U1] val u2 = session.build[U2] diff --git a/airspec/.jvm/src/test/scala/wvlet/airspec/TestExtension.scala b/airspec/.jvm/src/test/scala/wvlet/airspec/TestExtension.scala index 962a139e21..334e3932fc 100644 --- a/airspec/.jvm/src/test/scala/wvlet/airspec/TestExtension.scala +++ b/airspec/.jvm/src/test/scala/wvlet/airspec/TestExtension.scala @@ -43,7 +43,7 @@ trait MyServer extends LogSupport { trait CustomSpec extends AirSpec with LogSupport { protected val serverLaunchCounter = new AtomicInteger(0) - override def configure(design: Design): Design = { + override protected def configure(design: Design): Design = { design .bind[MyServer].toSingleton .bind[MyServerConfig].toInstance(MyServerConfig("A")) diff --git a/airspec/src/main/scala/wvlet/airspec/AirSpec.scala b/airspec/src/main/scala/wvlet/airspec/AirSpec.scala index 342f22409f..d657337fa8 100644 --- a/airspec/src/main/scala/wvlet/airspec/AirSpec.scala +++ b/airspec/src/main/scala/wvlet/airspec/AirSpec.scala @@ -68,16 +68,32 @@ private[airspec] trait AirSpecSpi { /** * Configure a global design for this spec. * + * @deprecated(message="Use design:Design instead", since="19.8.9") */ - protected def configure(design: Design): Design = design + protected def configure(d: Design): Design = d + design + + /** + * Provide a global design for this spec. + */ + protected def design: Design = Design.empty /** * Configure a test-case local design in the spec. * * Note that if you override a global design in this method, * test cases will create test-case local instances (singletons) + * + * @deprecated(message="Use localDesign: Design instead", since="19.8.9") + */ + protected def configureLocal(design: Design): Design = design + localDesign + + /** + * Provide a test-case local design in the spec. + * + * Note that if you override a global design in this method, + * test cases will create test-case local instances (singletons) */ - protected def configureLocal(design: Design): Design = design + protected def localDesign: Design = Design.empty protected def beforeAll: Unit = {} protected def before: Unit = {} diff --git a/airspec/src/main/scala/wvlet/airspec/spi/PropertyCheck.scala b/airspec/src/main/scala/wvlet/airspec/spi/PropertyCheck.scala index 045916346c..14f20088ab 100644 --- a/airspec/src/main/scala/wvlet/airspec/spi/PropertyCheck.scala +++ b/airspec/src/main/scala/wvlet/airspec/spi/PropertyCheck.scala @@ -46,7 +46,7 @@ trait PropertyCheck extends Asserts { this: AirSpecSpi => Prop(x) } - def forAll[A1, U](checker: A1 => U)( + protected def forAll[A1, U](checker: A1 => U)( implicit a1: Arbitrary[A1], s1: Shrink[A1], @@ -56,12 +56,12 @@ trait PropertyCheck extends Asserts { this: AirSpecSpi => checkProperty(prop) } - def forAll[A1, U](gen: Gen[A1])(checker: A1 => U)(implicit s1: Shrink[A1], pp1: A1 => Pretty): Unit = { + protected def forAll[A1, U](gen: Gen[A1])(checker: A1 => U)(implicit s1: Shrink[A1], pp1: A1 => Pretty): Unit = { val prop = Prop.forAll(gen)(checker.andThen(OK))(booleanProp, s1, pp1) checkProperty(prop) } - def forAll[A1, A2, U](checker: (A1, A2) => U)( + protected def forAll[A1, A2, U](checker: (A1, A2) => U)( implicit a1: Arbitrary[A1], s1: Shrink[A1], @@ -77,7 +77,7 @@ trait PropertyCheck extends Asserts { this: AirSpecSpi => checkProperty(prop) } - def forAll[A1, A2, U](g1: Gen[A1], g2: Gen[A2])(checker: (A1, A2) => U)( + protected def forAll[A1, A2, U](g1: Gen[A1], g2: Gen[A2])(checker: (A1, A2) => U)( implicit s1: Shrink[A1], pp1: A1 => Pretty, @@ -91,7 +91,7 @@ trait PropertyCheck extends Asserts { this: AirSpecSpi => checkProperty(prop) } - def forAll[A1, A2, A3, U](checker: (A1, A2, A3) => U)( + protected def forAll[A1, A2, A3, U](checker: (A1, A2, A3) => U)( implicit a1: Arbitrary[A1], s1: Shrink[A1], diff --git a/airspec/src/test/scala/examples/DITest.scala b/airspec/src/test/scala/examples/DITest.scala new file mode 100644 index 0000000000..a89d11526e --- /dev/null +++ b/airspec/src/test/scala/examples/DITest.scala @@ -0,0 +1,42 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package examples + +import wvlet.airframe.{Design, newDesign} +import wvlet.airspec.AirSpec + +/** + * + */ +class DITest extends AirSpec { + + import wvlet.airframe._ + + protected val v: Int = 1000 + + override protected def design: Design = newDesign.bind[String].toInstance("hello airframe") + override protected def localDesign: Design = newDesign.bind[Int].toInstance(v) + + def globalDesignTest(msg: String): Unit = { + msg shouldBe "hello airframe" + } + + def localDesignTest(intValue: Int): Unit = { + intValue shouldBe v + } +} + +class DIExtTest extends DITest { + override protected val v: Int = 2000 +} diff --git a/build.sbt b/build.sbt index 7889037e70..de8a133160 100644 --- a/build.sbt +++ b/build.sbt @@ -19,9 +19,9 @@ val JS_JAVA_LOGGING_VERSION = "0.1.5" val airSpecFramework = new TestFramework("wvlet.airspec.Framework") // Allow using Ctrl+C in sbt without exiting the prompt -cancelable in Global := true +// cancelable in Global := true -ThisBuild / turbo := true +//ThisBuild / turbo := true // For using Scala 2.12 in sbt scalaVersion in ThisBuild := SCALA_2_12