From bae61c487fc01e2c2fe8f2b9617af70a28d93dc7 Mon Sep 17 00:00:00 2001 From: "dmitry.shakhtarin" Date: Tue, 19 Jun 2018 16:33:31 +0300 Subject: [PATCH] parsing function for multiaddr string and tests --- .../scala/fluence/multiaddr/Multiaddr.scala | 55 +++++++++++++++++-- .../multiaddr/MultiaddrParseSpec.scala | 55 +++++++++++++++++++ 2 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 core/src/test/scala/fluence/multiaddr/MultiaddrParseSpec.scala diff --git a/core/src/main/scala/fluence/multiaddr/Multiaddr.scala b/core/src/main/scala/fluence/multiaddr/Multiaddr.scala index b3e52dd..1344a3d 100644 --- a/core/src/main/scala/fluence/multiaddr/Multiaddr.scala +++ b/core/src/main/scala/fluence/multiaddr/Multiaddr.scala @@ -17,10 +17,57 @@ package fluence.multiaddr -class Multiaddr { +import scala.annotation.tailrec -} +case class Multiaddr private(protocols: List[(Protocol, Option[String])]) object Multiaddr { - def fromNodeAddress(addr: String, transport: String): Either[Throwable, Multiaddr] = ??? -} \ No newline at end of file + + def apply(addr: String): Either[Throwable, Multiaddr] = { + if (!addr.startsWith("/")) { + Left(new IllegalArgumentException("Address must be started with '/'.")) + } else { + val parts = addr.stripPrefix("/").stripSuffix("/").split("/").toList + + if (parts.isEmpty) { + Left(new IllegalArgumentException("Address must be non-empty.")) + } else { + + parse(parts).map(protocols ⇒ new Multiaddr(protocols)) + } + } + } + + private def parse(list: List[String]): Either[Throwable, List[(Protocol, Option[String])]] = { + + @tailrec + def parseRec( + list: List[String], + res: Either[Throwable, List[(Protocol, Option[String])]] + ): Either[Throwable, List[(Protocol, Option[String])]] = { + list match { + case Nil ⇒ res + case head :: tail ⇒ + val protocolOp = Protocol.withNameOption(head) + + protocolOp match { + case None ⇒ + Left(new IllegalArgumentException(s"There is no protocol with name '$head'.")) + case Some(protocol) ⇒ + protocol.size match { + case 0 ⇒ parseRec(tail, res.map(els ⇒ els :+ (protocol, None))) + case _ ⇒ + tail match { + case Nil ⇒ + Left(new IllegalArgumentException(s"There is no parameter for protocol with name '$head'.")) + case innerHead :: innerTail ⇒ + parseRec(innerTail, res.map(els ⇒ els :+ (protocol, Some(innerHead)))) + } + } + } + } + } + + parseRec(list, Right(List.empty)) + } +} diff --git a/core/src/test/scala/fluence/multiaddr/MultiaddrParseSpec.scala b/core/src/test/scala/fluence/multiaddr/MultiaddrParseSpec.scala new file mode 100644 index 0000000..479c50a --- /dev/null +++ b/core/src/test/scala/fluence/multiaddr/MultiaddrParseSpec.scala @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2017 Fluence Labs Limited + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package fluence.multiaddr + +import org.scalatest.{Matchers, WordSpec} + +class MultiaddrParseSpec extends WordSpec with Matchers { + + import Protocol._ + + "multiaddr" should { + "throw exception if there is no leading '/'" in { + val m = Multiaddr("ip4/127.0.0.1/tcp/123") + m.isLeft shouldBe true + m.left.get.getMessage shouldBe "Address must be started with '/'." + } + + "parse correct multiaddresses right" in { + val m1 = Multiaddr("/ip4/127.0.0.1/tcp/123") + m1.isRight shouldBe true + m1.right.get.protocols shouldBe List((IP4, Some("127.0.0.1")), (TCP, Some("123"))) + + val m2 = Multiaddr("/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/udp/5000/https") + m2.isRight shouldBe true + m2.right.get.protocols shouldBe List((IP6, Some("2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095")), (UDP, Some("5000")), (HTTPS, None)) + } + + "throw exception if there is no protocol" in { + val m = Multiaddr("/ip4/127.0.0.1/tc/123") + m.isLeft shouldBe true + m.left.get.getMessage shouldBe "There is no protocol with name 'tc'." + } + + "throw exception if there is no parameter in protocol with parameter" in { + val m = Multiaddr("/ip4/127.0.0.1/tcp/") + m.isLeft shouldBe true + m.left.get.getMessage shouldBe "There is no parameter for protocol with name 'tcp'." + } + } +}