From 0013898d7628980f920dba7eed68153b36fd26fb Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sat, 17 Feb 2018 23:41:39 -0800 Subject: Update resolution tests in `MainTests.scala` Added test cases for new "Did you mean...", "Try `mill.resolve ...`" hints --- main/src/mill/main/Resolve.scala | 61 +++++++++++++++++--------- main/test/src/mill/eval/EvaluationTests.scala | 4 +- main/test/src/mill/main/MainTests.scala | 63 +++++++++++++++++++++------ 3 files changed, 92 insertions(+), 36 deletions(-) (limited to 'main') diff --git a/main/src/mill/main/Resolve.scala b/main/src/mill/main/Resolve.scala index 01c3dcf3..ccb5ec04 100644 --- a/main/src/mill/main/Resolve.scala +++ b/main/src/mill/main/Resolve.scala @@ -130,8 +130,6 @@ object ResolveTasks extends Resolve[NamedTask[Any]]{ command orElse target orElse Resolve.runDefault(obj, Segment.Label(last), discover, rest).flatten.headOption match { case None => - pprint.log(revSelectorsSoFar) - pprint.log(last) Resolve.errorMsgLabel( singleModuleMeta(obj, discover, revSelectorsSoFar.isEmpty), last, @@ -168,25 +166,26 @@ object Resolve{ def unableToResolve(segments: String): String = "Cannot resolve " + segments + "." - def hintList(last: Segment, revSelectorsSoFar: List[Segment]) = { - val search = Segments((last :: revSelectorsSoFar).reverse: _*).render + def hintList(revSelectorsSoFar: List[Segment]) = { + val search = Segments(revSelectorsSoFar.reverse: _*).render s" Try `mill resolve $search` to see what's available." } def hintListLabel(revSelectorsSoFar: List[Segment]) = { - hintList(Segment.Label("_"), revSelectorsSoFar) + hintList(Segment.Label("_") :: revSelectorsSoFar) } def hintListCross(revSelectorsSoFar: List[Segment]) = { - hintList(Segment.Cross(Seq("__")), revSelectorsSoFar) + hintList(Segment.Cross(Seq("__")) :: revSelectorsSoFar) } def errorMsgBase[T](direct: Seq[T], last0: T, revSelectorsSoFar: List[Segment], - editSplit: String => String) + editSplit: String => String, + defaultErrorMsg: String) (strings: T => Seq[String], - render: T => String)= { + render: T => String): Left[String, Nothing] = { val last = strings(last0) val similar = direct @@ -196,19 +195,29 @@ object Resolve{ .filter(_._2 < 3) .sortBy(_._2) - val hint = similar match{ - case Nil => hintListLabel(revSelectorsSoFar) - case items => - " Did you mean " + render(items.head._1)+ "?" + if (similar.headOption.exists(_._1 == last0)){ + // Special case: if the most similar segment is the desired segment itself, + // this means we are trying to resolve a module where a task is present. + // Special case the error message to make it something meaningful + Left("Task " + last0 + " is not a module and has no children.") + }else{ + + val hint = similar match{ + case Nil => defaultErrorMsg + case items => " Did you mean " + render(items.head._1) + "?" + } + Left(unableToResolve(render(last0)) + hint) } - pprint.log(direct) - pprint.log(revSelectorsSoFar) - pprint.log(last0) - pprint.log(last) - Left(unableToResolve(render(last0)) + hint) } + def errorMsgLabel(direct: Seq[String], last: String, revSelectorsSoFar: List[Segment]) = { - errorMsgBase(direct, Segments((Segment.Label(last) :: revSelectorsSoFar).reverse:_*).render, revSelectorsSoFar, _.split('.').last)( + errorMsgBase( + direct, + Segments((Segment.Label(last) :: revSelectorsSoFar).reverse:_*).render, + revSelectorsSoFar, + _.split('.').last, + hintListLabel(revSelectorsSoFar) + )( rendered => Seq(rendered.split('.').last), x => x ) @@ -217,7 +226,13 @@ object Resolve{ def errorMsgCross(crossKeys: Seq[Seq[String]], last: Seq[String], revSelectorsSoFar: List[Segment]) = { - errorMsgBase(crossKeys, last, revSelectorsSoFar, x => x)( + errorMsgBase( + crossKeys, + last, + revSelectorsSoFar, + x => x, + hintListCross(revSelectorsSoFar) + )( crossKeys => crossKeys, crossKeys => Segments((Segment.Cross(crossKeys) :: revSelectorsSoFar).reverse:_*).render ) @@ -308,11 +323,15 @@ abstract class Resolve[R: ClassTag] { .find(_.millOuterCtx.segment == Segment.Label(singleLabel)) .toSeq }, - Resolve.errorMsgLabel( + if (singleLabel != "_") Resolve.errorMsgLabel( singleModuleMeta(obj, discover, revSelectorsSoFar.isEmpty), singleLabel, revSelectorsSoFar ) + else Left( + "Cannot resolve " + Segments((remainingSelector.reverse ++ revSelectorsSoFar).reverse:_*).render + + ". Try `mill resolve " + Segments((Segment.Label("_") :: revSelectorsSoFar).reverse:_*).render + "` to see what's available" + ) ) case Segment.Cross(cross) => obj match{ @@ -329,7 +348,7 @@ abstract class Resolve[R: ClassTag] { Resolve.errorMsgCross( c.items.map(_._1.map(_.toString)), cross.map(_.toString), - newRevSelectorsSoFar + revSelectorsSoFar ) ) case _ => diff --git a/main/test/src/mill/eval/EvaluationTests.scala b/main/test/src/mill/eval/EvaluationTests.scala index e5f0e57d..da399449 100644 --- a/main/test/src/mill/eval/EvaluationTests.scala +++ b/main/test/src/mill/eval/EvaluationTests.scala @@ -211,7 +211,7 @@ object EvaluationTests extends TestSuite{ val public = ammonite.ops.read(checker.evaluator.outPath / 'foo / "meta.json") val overriden = ammonite.ops.read( checker.evaluator.outPath / 'foo / - 'overriden / "mill.util.TestGraphs.BaseModule#foo" / "meta.json" + 'overriden / "mill" / "util" / "TestGraphs" / "BaseModule#foo" / "meta.json" ) assert( public.contains("base"), @@ -239,7 +239,7 @@ object EvaluationTests extends TestSuite{ val public = ammonite.ops.read(checker.evaluator.outPath / 'cmd / "meta.json") val overriden = ammonite.ops.read( checker.evaluator.outPath / 'cmd / - 'overriden / "mill.util.TestGraphs.BaseModule#cmd" / "meta.json" + 'overriden / "mill" / "util" / "TestGraphs" / "BaseModule#cmd" / "meta.json" ) assert( public.contains("base1"), diff --git a/main/test/src/mill/main/MainTests.scala b/main/test/src/mill/main/MainTests.scala index 7ad5c00e..fbf193e1 100644 --- a/main/test/src/mill/main/MainTests.scala +++ b/main/test/src/mill/main/MainTests.scala @@ -27,19 +27,39 @@ object MainTests extends TestSuite{ 'single - { val check = MainTests.check(singleton) _ 'pos - check("single", Right(Seq(_.single))) - 'neg1 - check("doesntExist", Left("Cannot resolve doesntExist. Try `mill resolve _` to see what's available.")) - 'neg2 - check("single.doesntExist", Left("Cannot resolve single. Try `mill resolve _` to see what's available.")) - 'neg3 - check("", Left("Selector cannot be empty")) + 'neg1 - check("sngle", Left("Cannot resolve sngle. Did you mean single?")) + 'neg2 - check("snigle", Left("Cannot resolve snigle. Did you mean single?")) + 'neg3 - check("nsiigle", Left("Cannot resolve nsiigle. Did you mean single?")) + 'neg4 - check("ansiigle", Left("Cannot resolve ansiigle. Try `mill resolve _` to see what's available.")) + 'neg5 - check("doesntExist", Left("Cannot resolve doesntExist. Try `mill resolve _` to see what's available.")) + 'neg6 - check("single.doesntExist", Left("Task single is not a module and has no children.")) + 'neg7 - check("", Left("Selector cannot be empty")) } 'nested - { val check = MainTests.check(nestedModule) _ 'pos1 - check("single", Right(Seq(_.single))) 'pos2 - check("nested.single", Right(Seq(_.nested.single))) 'pos3 - check("classInstance.single", Right(Seq(_.classInstance.single))) - 'neg1 - check("doesntExist", Left("Cannot resolve doesntExist")) - 'neg2 - check("single.doesntExist", Left("Cannot resolve single")) - 'neg3 - check("nested.doesntExist", Left("Cannot resolve nested.doesntExist")) - 'neg4 - check("classInstance.doesntExist", Left("Cannot resolve classInstance.doesntExist")) + 'neg1 - check( + "doesntExist", + Left("Cannot resolve doesntExist. Try `mill resolve _` to see what's available.") + ) + 'neg2 - check( + "single.doesntExist", + Left("Task single is not a module and has no children.") + ) + 'neg3 - check( + "nested.doesntExist", + Left("Cannot resolve nested.doesntExist. Try `mill resolve nested._` to see what's available.") + ) + 'neg3 - check( + "nested.singel", + Left("Cannot resolve nested.singel. Did you mean nested.single?") + ) + 'neg4 - check( + "classInstance.doesntExist", + Left("Cannot resolve classInstance.doesntExist. Try `mill resolve classInstance._` to see what's available.") + ) 'wildcard - check( "_.single", Right(Seq( @@ -49,11 +69,15 @@ object MainTests extends TestSuite{ ) 'wildcardNeg - check( "_._.single", - Left("Cannot resolve _") + Left("Cannot resolve _._.single. Try `mill resolve _` to see what's available") ) 'wildcardNeg2 - check( "_._.__", - Left("Cannot resolve _") + Left("Cannot resolve _._.__. Try `mill resolve _` to see what's available") + ) + 'wildcardNeg3 - check( + "nested._.foobar", + Left("Cannot resolve nested._.foobar. Try `mill resolve nested._` to see what's available") ) 'wildcard2 - check( "__.single", @@ -78,9 +102,22 @@ object MainTests extends TestSuite{ val check = MainTests.check(singleCross) _ 'pos1 - check("cross[210].suffix", Right(Seq(_.cross("210").suffix))) 'pos2 - check("cross[211].suffix", Right(Seq(_.cross("211").suffix))) - 'neg1 - check("cross[210].doesntExist", Left("Cannot resolve cross[210].doesntExist")) - 'neg2 - check("cross[doesntExist].doesntExist", Left("Cannot resolve cross[doesntExist]")) - 'neg2 - check("cross[doesntExist].suffix", Left("Cannot resolve cross[doesntExist]")) + 'neg1 - check( + "cross[210].doesntExist", + Left("Cannot resolve cross[210].doesntExist. Try `mill resolve cross[210]._` to see what's available.") + ) + 'neg2 - check( + "cross[doesntExist].doesntExist", + Left("Cannot resolve cross[doesntExist]. Try `mill resolve cross[__]` to see what's available.") + ) + 'neg3 - check( + "cross[221].doesntExist", + Left("Cannot resolve cross[221]. Did you mean cross[211]?") + ) + 'neg4 - check( + "cross[doesntExist].suffix", + Left("Cannot resolve cross[doesntExist]. Try `mill resolve cross[__]` to see what's available.") + ) 'wildcard - check( "cross[_].suffix", Right(Seq( @@ -111,7 +148,7 @@ object MainTests extends TestSuite{ 'wildcard - { 'labelNeg - check( "_.suffix", - Left("Cannot resolve _.suffix") + Left("Cannot resolve _.suffix. Try `mill resolve _._` to see what's available.") ) 'labelPos - check( "__.suffix", -- cgit v1.2.3