diff --git a/morphir/src/org/finos/morphir/ir/gen1/Names.scala b/morphir/src/org/finos/morphir/ir/gen1/Names.scala new file mode 100644 index 000000000..c7caf4410 --- /dev/null +++ b/morphir/src/org/finos/morphir/ir/gen1/Names.scala @@ -0,0 +1,13 @@ +package org.finos.morphir.ir.gen1 + +trait Names + extends FQNameModule + with ModuleNameModule + with NameModule + with NamespaceModule + with NodeIDModule + with PathModule + with PackageNameModule + with QualifiedModuleNameModule + with QNameModule + with NamingOptionsModule diff --git a/morphir/src/org/finos/morphir/ir/gen1/NamingOptionsModule.scala b/morphir/src/org/finos/morphir/ir/gen1/NamingOptionsModule.scala new file mode 100644 index 000000000..6441d3aa0 --- /dev/null +++ b/morphir/src/org/finos/morphir/ir/gen1/NamingOptionsModule.scala @@ -0,0 +1,11 @@ +package org.finos.morphir.ir.gen1 + +trait NamingOptionsModule { self: PackageNameModule with ModuleNameModule => + + sealed case class FQNamingOptions(defaultPackage: PackageName, defaultModule: ModuleName, defaultSeparator: String) + + object FQNamingOptions { + implicit val default: FQNamingOptions = + FQNamingOptions(PackageName.empty, ModuleName.empty, ":") + } +} diff --git a/morphir/src/org/finos/morphir/ir/gen1/fqname.scala b/morphir/src/org/finos/morphir/ir/gen1/fqname.scala new file mode 100644 index 000000000..224742c55 --- /dev/null +++ b/morphir/src/org/finos/morphir/ir/gen1/fqname.scala @@ -0,0 +1,106 @@ +package org.finos.morphir.ir.gen1 + +trait FQNameModule { + self: NameModule with ModuleNameModule with NamespaceModule with PackageNameModule with PathModule + with QualifiedModuleNameModule + with QNameModule + with NamingOptionsModule => + + sealed case class FQName(packagePath: PackageName, modulePath: ModuleName, localName: Name) { self => + def getPackagePath: Path = packagePath.toPath + + def getModulePath: Path = modulePath.toPath + def getModuleName: ModuleName = modulePath + + /// An alias for `packagePath` + def pack: PackageName = packagePath + + def toReferenceName: String = Seq( + Path.toString(Name.toTitleCase, ".", packagePath.toPath), + Path.toString(Name.toTitleCase, ".", modulePath.toPath), + localName.toTitleCase + ).mkString(".") + + override def toString: String = Array( + Path.toString(Name.toTitleCase, ".", packagePath.toPath), + Path.toString(Name.toTitleCase, ".", modulePath.toPath), + Name.toCamelCase(localName) + ).mkString(":") + + def toStringTitleCase: String = Array( + Path.toString(Name.toTitleCase, ".", packagePath.toPath), + Path.toString(Name.toTitleCase, ".", modulePath.toPath), + Name.toTitleCase(this.localName) + ).mkString(":") + } + + object FQName { + val empty: FQName = FQName(PackageName.empty, ModuleName.empty, Name.empty) + // def apply(packagePath: Path, modulePath: Path, localName: Name): FQName = + // FQName(PackageName(packagePath), ModulePath(modulePath), localName) + + val fqName: Path => Path => Name => FQName = packagePath => + modulePath => localName => FQName(PackageName.fromPath(packagePath), ModuleName(modulePath), localName) + + def fromQName(packagePath: Path, qName: QName): FQName = + FQName(PackageName.fromPath(packagePath), ModuleName(qName.modulePath), qName.localName) + + def fromQName(qName: QName)(implicit packageName: PackageName): FQName = + FQName(packageName, ModuleName(qName.modulePath), qName.localName) + + def fromQName(qName: QName)(implicit options: FQNamingOptions): FQName = + FQName(options.defaultPackage, ModuleName(QName.getModulePath(qName)), QName.getLocalName(qName)) + + /** Get the package path part of a fully-qualified name. */ + def getPackagePath(fqName: FQName): Path = fqName.getPackagePath + + /** Get the module path part of a fully-qualified name */ + def getModulePath(fqName: FQName): Path = fqName.getModulePath + + /** Get the local name part of a fully-qualified name */ + def getLocalName(fqName: FQName): Name = fqName.localName + + /** Convenience function to create a fully-qualified name from 3 strings */ + def fqn(packageName: String, moduleName: String, localName: String): FQName = + FQName(PackageName.fromString(packageName), ModuleName.fromString(moduleName), Name.fromString(localName)) + + /** Convenience function to create a fully-qualified name from 2 strings with default package name */ + def fqn(moduleName: String, localName: String)(implicit options: FQNamingOptions): FQName = + FQName(options.defaultPackage, ModuleName(Path.fromString(moduleName)), Name.fromString(localName)) + + /** Convenience function to create a fully-qualified name from 1 string with defaults for package and module */ + def fqn(localName: String)(implicit options: FQNamingOptions): FQName = + FQName(options.defaultPackage, options.defaultModule, Name.fromString(localName)) + + /// Convenience function to create a fully-qualified name from a local name and an implicitly provided `QualifiedModuleName`. + def fromLocalName(localName: String)(implicit qualifiedModuleName: QualifiedModuleName): FQName = + FQName(qualifiedModuleName.packageName, qualifiedModuleName.modulePath, Name.fromString(localName)) + + def fromLocalName(localName: Name)(implicit qualifiedModuleName: QualifiedModuleName): FQName = + FQName(qualifiedModuleName.packageName, qualifiedModuleName.modulePath, localName) + + def toString(fqName: FQName): String = fqName.toString + + /** Parse a string into a FQName using splitter as the separator between package, module, and local names */ + def fromString(fqNameString: String, splitter: String)(implicit options: FQNamingOptions): FQName = + fqNameString.split(splitter) match { + case Array(packageNameString, moduleNameString, localNameString) => + fqn(packageNameString, moduleNameString, localNameString) + case Array(moduleNameString, localNameString) => + fqn(moduleNameString, localNameString) + case Array(localNameString) => + fqn(localNameString) + case _ => throw FQNameParsingError(fqNameString) + } + + def fromString(fqNameString: String)(implicit options: FQNamingOptions): FQName = + fromString(fqNameString, options.defaultSeparator) + + object ReferenceName { + def unapply(fqName: FQName): Some[String] = Some(fqName.toReferenceName) + } + } + + sealed case class FQNameParsingError(invalidName: String) + extends Exception(s"Unable to parse: [$invalidName] into a valid FQName") +} diff --git a/morphir/src/org/finos/morphir/ir/gen1/naming.scala b/morphir/src/org/finos/morphir/ir/gen1/naming.scala new file mode 100644 index 000000000..aa3e62aa0 --- /dev/null +++ b/morphir/src/org/finos/morphir/ir/gen1/naming.scala @@ -0,0 +1,55 @@ +package org.finos.morphir.ir.gen1 + +object naming extends Names { + + final implicit class PackageNameSyntax(val self: PackageName) extends AnyVal { + def /(moduleName: ModuleName): QualifiedModuleName = QualifiedModuleName(self, moduleName) + } + + final implicit class QualifiedModuleNameSyntax(val self: QualifiedModuleName) extends AnyVal { + def %(localName: String): FQName = FQName(self.packageName, self.modulePath, Name.fromString(localName)) + def %(name: Name): FQName = FQName(self.packageName, self.modulePath, name) + } + + final implicit class NamingHelper(val sc: StringContext) extends AnyVal { + + def fqn(args: Any*): FQName = { + val interlaced = interlace(sc.parts, args.map(_.toString)) + FQName.fromString(interlaced.mkString) + } + + def mod(args: Any*): ModuleName = { + val interlaced = interlace(sc.parts, args.map(_.toString)) + ModuleName.fromString(interlaced.mkString) + } + + def n(args: Any*): Name = { + val interlaced = interlace(sc.parts, args.map(_.toString)) + Name.fromString(interlaced.mkString) + } + + def qmn(args: Any*): QualifiedModuleName = { + val interlaced = interlace(sc.parts, args.map(_.toString)) + QualifiedModuleName.fromString(interlaced.mkString) + } + + def name(args: Any*): Name = { + val interlaced = interlace(sc.parts, args.map(_.toString)) + Name.fromString(interlaced.mkString) + } + + def pkg(args: Any*): PackageName = { + val interlaced = interlace(sc.parts, args.map(_.toString)) + PackageName.fromString(interlaced.mkString) + } + + def path(args: Any*): Path = { + val interlaced = interlace(sc.parts, args.map(_.toString)) + Path.fromString(interlaced.mkString) + } + } + + private[morphir] def interlace[T](a: Iterable[T], b: Iterable[T]): List[T] = + if (a.isEmpty) b.toList + else a.head +: interlace(b, a.tail) +} diff --git a/morphir/src/org/finos/morphir/ir/gen1/nodeID.scala b/morphir/src/org/finos/morphir/ir/gen1/nodeID.scala new file mode 100644 index 000000000..355ac93fe --- /dev/null +++ b/morphir/src/org/finos/morphir/ir/gen1/nodeID.scala @@ -0,0 +1,158 @@ +package org.finos.morphir.ir.gen1 + +trait NodeIDModule { + self: FQNameModule with NamingOptionsModule with NameModule with PathModule with PackageNameModule + with ModuleNameModule + with QualifiedModuleNameModule => + import NodePath.* + + /** Represents a path in the IR. + * ==Overview== + * A NodeID can have two slightly different structures depending on if we are refering to modules or definitions + * (types/values). + * + * - When refefering to modules: `"module::"` + * - When refering to definitions: `"type\value::#"`, where nodePath is + * optional + * + * Examples of valid NodeIDs: + * - "module:Morphir.Reference.Model:BooksAndRecords" + * - "type:Morphir.Reference.Model:BooksAndRecords:deal" + * - "value:Morphir.Reference.Model:BooksAndRecords:deal#1" + * + * ==Referring to modules== + * We can refer to modules by their Qualified Name, with the module: prefix + * + * For example: `"module:Morphir.Reference.Model:BooksAndRecords"` refers to the `Books and Records` module inside + * the `Morphir.Reference.Model` package. + */ + sealed trait NodeID extends Product with Serializable { self => + import NodeID.* + override def toString(): String = { + implicit val renderer: PathRenderer = PathRenderer.TitleCase + def mapToTypeOrValue( + packageName: Path, + moduleName: Path, + localName: Name, + suffix: String, + nodePath: NodePath + ): String = { + val nodeIdString = s"${packageName.render}:${moduleName.render}:${localName.toCamelCase}$suffix" + nodePath match { + case NodePath(Vector()) => nodeIdString + case _ => s"$nodeIdString$nodePath" + } + } + + self match { + case ModuleID(packagePath, modulePath) => + s"${packagePath.path.render}:${modulePath.path.render}" + case TypeID(FQName(packageName, moduleName, localName), path) => + mapToTypeOrValue(packageName.path, moduleName.path, localName, ".type", path) + case ValueID(FQName(packageName, moduleName, localName), path) => + mapToTypeOrValue(packageName.path, moduleName.path, localName, ".value", path) + } + } + } + type NodeIDCompanion = NodeID.type + object NodeID { + + def fromQualifiedName(qualifiedModuleName: QualifiedModuleName): NodeID = + ModuleID.fromQualifiedName(qualifiedModuleName) + + def fromString(input: String): Either[Error, NodeID] = { + def mapToTypeOrValue(packageName: String, moduleName: String, defNameWithSuffix: String, nodePath: String) = { + def defName(suffix: String) = defNameWithSuffix.dropRight(suffix.length()) + if (defNameWithSuffix.endsWith(".value")) + Right(ValueID(FQName.fqn(packageName, moduleName, defName(".value")), NodePath.fromString(nodePath))) + else + Right(TypeID(FQName.fqn(packageName, moduleName, defName(".type")), NodePath.fromString(nodePath))) + } + + input.split(":") match { + case Array(packageName, moduleName) => + Right(ModuleID(Path(packageName), Path(moduleName))) + case Array(packageName, moduleName, localName) => + if (localName.contains("#")) + localName.split("#") match { + case Array(defName, path) => mapToTypeOrValue(packageName, moduleName, defName, path) + case _ => Left(Error.InvalidNodeId(input)) + } + else + mapToTypeOrValue(packageName, moduleName, localName, "") + case _ => + Left(Error.InvalidNodeId(input)) + } + } + + sealed case class TypeID(name: FQName, memberPath: NodePath) extends NodeID + sealed case class ValueID(name: FQName, memberPath: NodePath) extends NodeID + sealed case class ModuleID(packageName: PackageName, moduleName: ModuleName) extends NodeID + object ModuleID { + def apply(packagePath: Path, modulePath: Path): ModuleID = + ModuleID(PackageName(packagePath), ModuleName(modulePath)) + + def fromQualifiedName(qualifiedModuleName: QualifiedModuleName): ModuleID = + ModuleID(qualifiedModuleName.packageName, qualifiedModuleName.modulePath) + } + + sealed abstract class Error(errorMessage: String) extends Exception(errorMessage) + object Error { + sealed case class InvalidPath(input: String, errorMessage: String) extends Error(errorMessage) + sealed case class InvalidNodeId(input: String, errorMessage: String) extends Error(errorMessage) { + def this(input: String) = this(input, s"Invalid NodeId: $input") + } + + object InvalidNodeId { + def apply(input: String): InvalidNodeId = new InvalidNodeId(input) + } + } + } + + sealed case class NodePath(steps: Vector[NodePathStep]) { self => + import NodePathStep.* + + def /(step: NodePathStep): NodePath = NodePath(steps :+ step) + def /(name: String): NodePath = self / ChildByName(Name.fromString(name)) + + @inline def isEmpty: Boolean = steps.isEmpty + + override def toString(): String = + if (self.isEmpty) "" + else + steps.map { + case ChildByName(name) => name.toCamelCase + case ChildByIndex(index) => index.toString() + }.mkString("#", ":", "") + } + + object NodePath { + import NodePathStep.* + val empty: NodePath = NodePath(Vector.empty) + + @inline def fromIterable(iterable: Iterable[NodePathStep]): NodePath = NodePath(iterable.toVector) + + def fromString(input: String): NodePath = + if (input.isEmpty()) empty + else + fromIterable(input.split(":").map { stepString => + stepString.toIntOption match { + case Some(index) => NodePathStep.childByIndex(index) + case None => NodePathStep.childByName(stepString) + } + }) + } + + sealed trait NodePathStep + object NodePathStep { + def childByName(input: String): NodePathStep = ChildByName(Name.fromString(input)) + def childByIndex(index: Int): NodePathStep = ChildByIndex(index) + + sealed case class ChildByName(name: Name) extends NodePathStep + sealed case class ChildByIndex(index: Int) extends NodePathStep + } + + trait HasId { + def id: NodeID + } +} diff --git a/morphir/src/org/finos/morphir/ir/gen1/packageName.scala b/morphir/src/org/finos/morphir/ir/gen1/packageName.scala new file mode 100644 index 000000000..af76b271c --- /dev/null +++ b/morphir/src/org/finos/morphir/ir/gen1/packageName.scala @@ -0,0 +1,44 @@ +package org.finos.morphir.ir.gen1 + +trait PackageNameModule { self: Names => + + /** A package name is a globally unique identifier for a package. It is represented by a `Path` which is a list of + * names. + */ + sealed case class PackageName(path: Path) { self => + def ++(that: PackageName): PackageName = PackageName(path ++ that.path) + def ++(that: Path): PackageName = PackageName(path ++ that) + def /(pathString: String): PackageName = PackageName(path ++ Path.fromString(pathString)) + + @deprecated("Use `%(moduleName: ModuleName)` instead", "0.4.0-M3") + def /(moduleName: ModuleName): QualifiedModuleName = QualifiedModuleName(self, moduleName) + def %(modulePath: String): QualifiedModuleName = QualifiedModuleName(self, ModuleName.fromString(modulePath)) + def %(moduleName: ModuleName): QualifiedModuleName = QualifiedModuleName(self, moduleName) + + @inline def isEmpty: Boolean = path.isEmpty + @inline def toPath: Path = path + + def render(implicit renderer: PathRenderer): String = renderer(path) + /// An alias for `render` + def show(implicit renderer: PathRenderer): String = render + override def toString(): String = render + } + + val root = PackageName.root + + object PackageName { + val empty: PackageName = PackageName(Path.empty) + val root: PackageName = PackageName(Path.empty) + + // val morphirSdk:PackageName = PackageName.fromString("Morphir.SDK") + + def fromPath(path: Path): PackageName = PackageName(path) + + def fromString(str: String): PackageName = PackageName(Path.fromString(str)) + def fromIterable(segments: Iterable[Name]): PackageName = + PackageName(Path.fromIterable(segments)) + def fromList(segments: List[Name]): PackageName = + PackageName(Path.fromList(segments)) + + } +} diff --git a/morphir/src/org/finos/morphir/ir/gen1/qualifiedModuleName.scala b/morphir/src/org/finos/morphir/ir/gen1/qualifiedModuleName.scala new file mode 100644 index 000000000..1357c06aa --- /dev/null +++ b/morphir/src/org/finos/morphir/ir/gen1/qualifiedModuleName.scala @@ -0,0 +1,60 @@ +package org.finos.morphir.ir.gen1 + +trait QualifiedModuleNameModule { + self: NameModule with PackageNameModule with PathModule with ModuleNameModule with NamespaceModule + with NamingOptionsModule => + + /// A qualified module name is a globally unique identifier for a module. It is represented by the combination of a package name and the module name. + sealed case class QualifiedModuleName(packageName: PackageName, modulePath: ModuleName) { self => + def /(moduleName: ModuleName): QualifiedModuleName = + QualifiedModuleName(self.packageName, self.modulePath ++ moduleName) + def /(namespaceAddition: String): QualifiedModuleName = + QualifiedModuleName(self.packageName, modulePath.addPart(namespaceAddition)) + + def toTuple: (Path, Path) = (packageName.toPath, modulePath.toPath) + + override def toString: String = Array( + Path.toString(Name.toTitleCase, ".", packageName.toPath), + Path.toString(Name.toTitleCase, ".", modulePath.toPath) + ).mkString(":") + } + + object QualifiedModuleName { + val empty: QualifiedModuleName = QualifiedModuleName(PackageName.empty, ModuleName.empty) + + def apply(packageName: Path, modulePath: Path): QualifiedModuleName = + QualifiedModuleName(PackageName.fromPath(packageName), ModuleName(modulePath)) + + def apply(modulePath: String)(implicit packageName: PackageName): QualifiedModuleName = + QualifiedModuleName(packageName, ModuleName.fromString(modulePath)) + + /** Parse a string into a QualifedModuleName using splitter as the separator between package, and module */ + def fromString(nameString: String, splitter: String)(implicit options: FQNamingOptions): QualifiedModuleName = + nameString.split(splitter) match { + case Array(moduleNameString, localNameString) => + qmn(moduleNameString, localNameString) + case Array(localNameString) => + qmn(localNameString) + case _ => throw QualifiedModuleNameParsingError(nameString) + } + + def fromString(fqNameString: String)(implicit options: FQNamingOptions): QualifiedModuleName = + fromString(fqNameString, options.defaultSeparator) + + /** Convenience function to create a fully-qualified name from 2 strings with default package name */ + def qmn(packageName: String, moduleName: String): QualifiedModuleName = + QualifiedModuleName(PackageName.fromString(packageName), ModuleName(Path.fromString(moduleName))) + + /** Convenience function to create a fully-qualified name from 1 string with defaults for package and module */ + def qmn(moduleName: String)(implicit options: FQNamingOptions): QualifiedModuleName = + QualifiedModuleName(options.defaultPackage, ModuleName(Path.fromString(moduleName))) + + object AsTuple { + def unapply(name: QualifiedModuleName): Option[(Path, Path)] = + Some(name.toTuple) + } + } + + sealed case class QualifiedModuleNameParsingError(invalidName: String) + extends Exception(s"Unable to parse: [$invalidName] into a valid QualifiedModuleName") +} diff --git a/morphir/test/src/org/finos/morphir/ir/gen1/FQNameSpec.scala b/morphir/test/src/org/finos/morphir/ir/gen1/FQNameSpec.scala index 3f8acf386..caaf43fb6 100644 --- a/morphir/test/src/org/finos/morphir/ir/gen1/FQNameSpec.scala +++ b/morphir/test/src/org/finos/morphir/ir/gen1/FQNameSpec.scala @@ -1,191 +1,23 @@ package org.finos.morphir.ir.gen1 -//import zio.test.Assertion.* -//import zio.test.* -// -//object FQNameSpec extends MorphirSpecDefault { -// def spec = suite("FQNameSpec")( -// suite("Create a FQName:")( -// test("By using a string") { -// assertTrue( -// FQName.fromString("moduleName/packageName/localName", "/") == -// FQName( -// PackageName(Path.fromString("moduleName")), -// ModuleName(Path.fromString("packageName")), -// Name.fromString("localName") -// ) -// ) -// }, -// test("By using a QName with package name") { -// implicit val packageName = PackageName.fromString("package Name") -// val qName = QName(Path.fromString("qualified.Name.Path"), Name.fromString("localName")) -// assertTrue(FQName.fromQName(qName) == FQName(packageName, qName.moduleName, qName.localName)) -// }, -// test("By using a QName without package name using implicit defaults") { -// val pkg = PackageName(Path.fromString("package Name")) -// implicit val default: FQNamingOptions = FQNamingOptions(pkg, ModuleName(Path.fromString("MyModule")), ":") -// val qName = QName(Path.fromString("qualified.Name.Path"), Name.fromString("localName")) -// assertTrue(FQName.fromQName(qName) == FQName(pkg, ModuleName(qName.modulePath), qName.localName)) -// } -// ), -// suite("Retrieving variables should work")( -// test("Get PackagePath") { -// val fqName = FQName.fromString("moduleName/packageName/localName", "/") -// assertTrue(FQName.getPackagePath(fqName) == Path.fromString("moduleName")) -// }, -// test("Get ModulePath") { -// val fqName = FQName.fromString("moduleName/packageName/localName", "/") -// assertTrue(FQName.getModulePath(fqName) == Path.fromString("packageName")) -// }, -// test("Get localName") { -// val fqName = FQName.fromString("moduleName/packageName/localName", "/") -// assertTrue(FQName.getLocalName(fqName) == Name.fromString("localName")) -// } -// ), -// suite("Creating a string from FQName") { -// test("should work") { -// assertTrue( -// FQName.toString( -// FQName( -// PackageName(Path.fromString("com.example")), -// ModuleName(Path.fromString("java home")), -// Name.fromString("morphir") -// ) -// ) == "Com.Example:JavaHome:morphir" -// ) -// } -// }, -// suite("Creating FQName from a string")( -// test("3 parameters")( -// assertTrue( -// FQName.fromString("Com.Example:JavaHome:morphir", ":") == -// FQName( -// PackageName(Path.fromString("com.example")), -// ModuleName(Path.fromString("JavaHome")), -// Name.fromString("morphir") -// ) -// ) -// ), -// test("3 parameters - different splitter")( -// assertTrue( -// FQName.fromString("Com.Example;JavaHome;morphir", ";") == -// FQName( -// PackageName(Path.fromString("com.example")), -// ModuleName(Path.fromString("JavaHome")), -// Name.fromString("morphir") -// ) -// ) -// ), -// test("3 parameters - with implicit FQNamingOptions") { -// implicit val default: FQNamingOptions = FQNamingOptions(PackageName(Path.empty), ModuleName(Path.empty), ";") -// -// assertTrue( -// FQName.fromString("Com.Example;JavaHome;morphir") == -// FQName( -// PackageName(Path.fromString("com.example")), -// ModuleName(Path.fromString("JavaHome")), -// Name.fromString("morphir") -// ) -// ) -// }, -// test("2 parameters")( -// assertTrue( -// FQName.fromString("scalaHome:morphir") == -// FQName( -// PackageName(Path.empty), -// ModuleName(Path.fromString("scalaHome")), -// Name.fromString("morphir") -// ) -// ) -// ), -// test("2 parameters - with implicit FQNamingOptions") { -// implicit val default: FQNamingOptions = -// FQNamingOptions(PackageName(Path.fromString("zio.test")), ModuleName(Path.fromString("MyModule")), ";") -// -// assertTrue( -// FQName.fromString("JavaHome;morphir") == -// FQName( -// PackageName(Path.fromString("zio.test")), -// ModuleName(Path.fromString("JavaHome")), -// Name.fromString("morphir") -// ) -// ) -// }, -// test("1 parameter")( -// assertTrue( -// FQName.fromString("morphir") == FQName( -// PackageName(Path.empty), -// ModuleName(Path.empty), -// Name.fromString("morphir") -// ) -// ) -// ), -// test("1 parameters - with implicit FQNamingOptions") { -// implicit val default: FQNamingOptions = -// FQNamingOptions(PackageName(Path.fromString("zio.test")), ModuleName(Path.fromString("MyModule")), ";") -// -// assertTrue( -// FQName.fromString("morphir") == -// FQName( -// PackageName(Path.fromString("zio.test")), -// ModuleName(Path.fromString("MyModule")), -// Name.fromString("morphir") -// ) -// ) -// }, -// test("empty string - empty path")( -// assertTrue( -// FQName.fromString("") == -// FQName( -// PackageName(Path.empty), -// ModuleName(Path.empty), -// Name.fromString("") -// ) -// ) -// ), -// test("4 or more parameters - throws ParserError")( -// assert(FQName.fromString("abc:bcd:cde:def", ":"))(throwsA[ParserError]) && -// assert(FQName.fromString("abc:bcd:cde:def:efg", ":"))(throwsA[ParserError]) -// ), -// test("other variations for throwing ParserError")( -// assert(FQName.fromString(":", ":"))(throwsA[ParserError]) && -// assert(FQName.fromString(":"))(throwsA[ParserError]) && -// assert(FQName.fromString("-", "-"))(throwsA[ParserError]) && -// assert(FQName.fromString("::", ":"))(throwsA[ParserError]) && -// assert(FQName.fromString("::"))(throwsA[ParserError]) && -// assert(FQName.fromString(";;", ";"))(throwsA[ParserError]) -// ) -// ), -// suite("getModuleName")( -// test("When Path and LocalName are compound") { -// val sut = FQName.fromString(":morphir.sdk:local.date") -// assertTrue( -// sut.getModuleName == QualifiedModuleName(Path.fromString("morphir.sdk"), Name.fromString("LocalDate")) -// ) -// } -// ) -// ) -//} -//package org.finos.morphir.ir -//import org.finos.morphir.naming.* -//import org.finos.morphir.datamodel.namespacing.{PackageName => Pack, *} -//import org.finos.morphir.testing.MorphirSpecDefault -//import zio.test.Assertion.* -//import zio.test.* -// -//object FQNameSpec extends MorphirSpecDefault { -// def spec = suite("FQNameSpec")( -// suite("Create a FQName:")( -// test("By using a string") { -// assertTrue( -// FQName.fromString("moduleName/packageName/localName", "/") == -// FQName( -// PackageName(Path.fromString("moduleName")), -// ModuleName(Path.fromString("packageName")), -// Name.fromString("localName") -// ) -// ) -// }, +import org.finos.morphir.ir.gen1.naming.* +import org.finos.morphir.testing.MorphirSpecDefault +import zio.test.Assertion.* +import zio.test.* + +object FQNameSpec extends MorphirSpecDefault { + def spec = suite("FQNameSpec")( + suite("Create a FQName:")( + test("By using a string") { + assertTrue( + FQName.fromString("moduleName/packageName/localName", "/") == + FQName( + PackageName(Path.fromString("moduleName")), + ModuleName(Path.fromString("packageName")), + Name.fromString("localName") + ) + ) + } // test("By using a QName with package name") { // implicit val packageName = PackageName.fromString("package Name") // val qName = QName(Path.fromString("qualified.Name.Path"), Name.fromString("localName")) @@ -197,135 +29,135 @@ package org.finos.morphir.ir.gen1 // val qName = QName(Path.fromString("qualified.Name.Path"), Name.fromString("localName")) // assertTrue(FQName.fromQName(qName) == FQName(pkg, ModuleName(qName.modulePath), qName.localName)) // } -// ), -// suite("Retrieving variables should work")( -// test("Get PackagePath") { -// val fqName = FQName.fromString("moduleName/packageName/localName", "/") -// assertTrue(FQName.getPackagePath(fqName) == Path.fromString("moduleName")) -// }, -// test("Get ModulePath") { -// val fqName = FQName.fromString("moduleName/packageName/localName", "/") -// assertTrue(FQName.getModulePath(fqName) == Path.fromString("packageName")) -// }, -// test("Get localName") { -// val fqName = FQName.fromString("moduleName/packageName/localName", "/") -// assertTrue(FQName.getLocalName(fqName) == Name.fromString("localName")) -// } -// ), -// suite("Creating a string from FQName") { -// test("should work") { -// assertTrue( -// FQName.toString( -// FQName( -// PackageName(Path.fromString("com.example")), -// ModuleName(Path.fromString("java home")), -// Name.fromString("morphir") -// ) -// ) == "Com.Example:JavaHome:morphir" -// ) -// } -// }, -// suite("Creating FQName from a string")( -// test("3 parameters")( -// assertTrue( -// FQName.fromString("Com.Example:JavaHome:morphir", ":") == -// FQName( -// PackageName(Path.fromString("com.example")), -// ModuleName(Path.fromString("JavaHome")), -// Name.fromString("morphir") -// ) -// ) -// ), -// test("3 parameters - different splitter")( -// assertTrue( -// FQName.fromString("Com.Example;JavaHome;morphir", ";") == -// FQName( -// PackageName(Path.fromString("com.example")), -// ModuleName(Path.fromString("JavaHome")), -// Name.fromString("morphir") -// ) -// ) -// ), -// test("3 parameters - with implicit FQNamingOptions") { -// implicit val default: FQNamingOptions = FQNamingOptions(PackageName(Path.empty), ModuleName(Path.empty), ";") -// -// assertTrue( -// FQName.fromString("Com.Example;JavaHome;morphir") == -// FQName( -// PackageName(Path.fromString("com.example")), -// ModuleName(Path.fromString("JavaHome")), -// Name.fromString("morphir") -// ) -// ) -// }, -// test("2 parameters")( -// assertTrue( -// FQName.fromString("scalaHome:morphir") == -// FQName( -// PackageName(Path.empty), -// ModuleName(Path.fromString("scalaHome")), -// Name.fromString("morphir") -// ) -// ) -// ), -// test("2 parameters - with implicit FQNamingOptions") { -// implicit val default: FQNamingOptions = -// FQNamingOptions(PackageName(Path.fromString("zio.test")), ModuleName(Path.fromString("MyModule")), ";") -// -// assertTrue( -// FQName.fromString("JavaHome;morphir") == -// FQName( -// PackageName(Path.fromString("zio.test")), -// ModuleName(Path.fromString("JavaHome")), -// Name.fromString("morphir") -// ) -// ) -// }, -// test("1 parameter")( -// assertTrue( -// FQName.fromString("morphir") == FQName( -// PackageName(Path.empty), -// ModuleName(Path.empty), -// Name.fromString("morphir") -// ) -// ) -// ), -// test("1 parameters - with implicit FQNamingOptions") { -// implicit val default: FQNamingOptions = -// FQNamingOptions(PackageName(Path.fromString("zio.test")), ModuleName(Path.fromString("MyModule")), ";") -// -// assertTrue( -// FQName.fromString("morphir") == -// FQName( -// PackageName(Path.fromString("zio.test")), -// ModuleName(Path.fromString("MyModule")), -// Name.fromString("morphir") -// ) -// ) -// }, -// test("empty string - empty path")( -// assertTrue( -// FQName.fromString("") == -// FQName( -// PackageName(Path.empty), -// ModuleName(Path.empty), -// Name.fromString("") -// ) -// ) -// ), + ), + suite("Retrieving variables should work")( + test("Get PackagePath") { + val fqName = FQName.fromString("moduleName/packageName/localName", "/") + assertTrue(FQName.getPackagePath(fqName) == Path.fromString("moduleName")) + }, + test("Get ModulePath") { + val fqName = FQName.fromString("moduleName/packageName/localName", "/") + assertTrue(FQName.getModulePath(fqName) == Path.fromString("packageName")) + }, + test("Get localName") { + val fqName = FQName.fromString("moduleName/packageName/localName", "/") + assertTrue(FQName.getLocalName(fqName) == Name.fromString("localName")) + } + ), + suite("Creating a string from FQName") { + test("should work") { + assertTrue( + FQName.toString( + FQName( + PackageName(Path.fromString("com.example")), + ModuleName(Path.fromString("java home")), + Name.fromString("morphir") + ) + ) == "Com.Example:JavaHome:morphir" + ) + } + }, + suite("Creating FQName from a string")( + test("3 parameters")( + assertTrue( + FQName.fromString("Com.Example:JavaHome:morphir", ":") == + FQName( + PackageName(Path.fromString("com.example")), + ModuleName(Path.fromString("JavaHome")), + Name.fromString("morphir") + ) + ) + ), + test("3 parameters - different splitter")( + assertTrue( + FQName.fromString("Com.Example;JavaHome;morphir", ";") == + FQName( + PackageName(Path.fromString("com.example")), + ModuleName(Path.fromString("JavaHome")), + Name.fromString("morphir") + ) + ) + ), + test("3 parameters - with implicit FQNamingOptions") { + implicit val default: FQNamingOptions = FQNamingOptions(PackageName(Path.empty), ModuleName(Path.empty), ";") + + assertTrue( + FQName.fromString("Com.Example;JavaHome;morphir") == + FQName( + PackageName(Path.fromString("com.example")), + ModuleName(Path.fromString("JavaHome")), + Name.fromString("morphir") + ) + ) + }, + test("2 parameters")( + assertTrue( + FQName.fromString("scalaHome:morphir") == + FQName( + PackageName(Path.empty), + ModuleName(Path.fromString("scalaHome")), + Name.fromString("morphir") + ) + ) + ), + test("2 parameters - with implicit FQNamingOptions") { + implicit val default: FQNamingOptions = + FQNamingOptions(PackageName(Path.fromString("zio.test")), ModuleName(Path.fromString("MyModule")), ";") + + assertTrue( + FQName.fromString("JavaHome;morphir") == + FQName( + PackageName(Path.fromString("zio.test")), + ModuleName(Path.fromString("JavaHome")), + Name.fromString("morphir") + ) + ) + }, + test("1 parameter")( + assertTrue( + FQName.fromString("morphir") == FQName( + PackageName(Path.empty), + ModuleName(Path.empty), + Name.fromString("morphir") + ) + ) + ), + test("1 parameters - with implicit FQNamingOptions") { + implicit val default: FQNamingOptions = + FQNamingOptions(PackageName(Path.fromString("zio.test")), ModuleName(Path.fromString("MyModule")), ";") + + assertTrue( + FQName.fromString("morphir") == + FQName( + PackageName(Path.fromString("zio.test")), + ModuleName(Path.fromString("MyModule")), + Name.fromString("morphir") + ) + ) + }, + test("empty string - empty path")( + assertTrue( + FQName.fromString("") == + FQName( + PackageName(Path.empty), + ModuleName(Path.empty), + Name.fromString("") + ) + ) + ) // test("4 or more parameters - throws ParserError")( // assert(FQName.fromString("abc:bcd:cde:def", ":"))(throwsA[ParserError]) && -// assert(FQName.fromString("abc:bcd:cde:def:efg", ":"))(throwsA[ParserError]) +// assert(FQName.fromString("abc:bcd:cde:def:efg", ":"))(throwsA[ParserError]) // ), // test("other variations for throwing ParserError")( // assert(FQName.fromString(":", ":"))(throwsA[ParserError]) && -// assert(FQName.fromString(":"))(throwsA[ParserError]) && -// assert(FQName.fromString("-", "-"))(throwsA[ParserError]) && -// assert(FQName.fromString("::", ":"))(throwsA[ParserError]) && -// assert(FQName.fromString("::"))(throwsA[ParserError]) && -// assert(FQName.fromString(";;", ";"))(throwsA[ParserError]) +// assert(FQName.fromString(":"))(throwsA[ParserError]) && +// assert(FQName.fromString("-", "-"))(throwsA[ParserError]) && +// assert(FQName.fromString("::", ":"))(throwsA[ParserError]) && +// assert(FQName.fromString("::"))(throwsA[ParserError]) && +// assert(FQName.fromString(";;", ";"))(throwsA[ParserError]) // ) -// ), + ) // suite("getModuleName")( // test("When Path and LocalName are compound") { // val sut = FQName.fromString(":morphir.sdk:local.date") @@ -334,5 +166,5 @@ package org.finos.morphir.ir.gen1 // ) // } // ) -// ) -//} + ) +} diff --git a/morphir/test/src/org/finos/morphir/ir/gen1/NameSpec.scala b/morphir/test/src/org/finos/morphir/ir/gen1/NameSpec.scala index 68c42d9ff..c788d3693 100644 --- a/morphir/test/src/org/finos/morphir/ir/gen1/NameSpec.scala +++ b/morphir/test/src/org/finos/morphir/ir/gen1/NameSpec.scala @@ -1,143 +1,143 @@ package org.finos.morphir.ir.gen1 -import org.finos.morphir.ir.gen1.* +import org.finos.morphir.ir.gen1.naming.* import org.finos.morphir.testing.MorphirSpecDefault import zio.test.* -//object NameSpec extends MorphirSpecDefault { -// def spec = suite("Name")( -// suite("Create a Name from a string and check that:")( -// suite("Name should be creatable from a single word that:")( -// test("Starts with a capital letter") { -// assertTrue(Name.fromString("Marco") == Name("marco")) -// }, -// test("Is all lowercase") { -// assertTrue(Name.fromString("polo") == Name("polo")) -// } -// ), -// suite("Name should be creatable from compound words that:")( -// test("Are formed from a snake case word") { -// assertTrue(Name.fromString("super_mario_world") == Name("super", "mario", "world")) -// }, -// test("Contain many kinds of word delimiters") { -// assertTrue(Name.fromString("fooBar_baz 123") == Name("foo", "bar", "baz", "123")) -// }, -// test("Are formed from a camel-cased string") { -// assertTrue(Name.fromString("valueInUSD") == Name("value", "in", "u", "s", "d")) -// }, -// test("Are formed from a title-cased string") { -// assertTrue( -// Name.fromString("ValueInUSD") == Name("value", "in", "u", "s", "d"), -// Name.fromString("ValueInJPY") == Name("value", "in", "j", "p", "y") -// ) -// }, -// test("Have a number in the middle") { -// assertTrue(Name.fromString("Nintendo64VideoGameSystem") == Name("nintendo", "64", "video", "game", "system")) -// }, -// test("Are complete and utter nonsense") { -// assertTrue(Name.fromString("_-%") == Name.empty) -// } -// ), -// test("It splits the name as expected") { -// // "fooBar","blahBlah" => ["foo","bar","blah","blah"] -// // "fooBar","blahBlah" => ["fooBar","blahBlah"] -// assertTrue( -// Name.fromString("fooBar").toList == List("foo", "bar") -// ) -// } -// ), -// suite("Name should be convertible to a title-case string:")( -// test("When the name was originally constructed from a snake-case string") { -// val sut = Name.fromString("snake_case_input") -// assertTrue(Name.toTitleCase(sut) == "SnakeCaseInput") -// }, -// test( -// "When the name was originally constructed from a camel-case string" -// ) { -// val sut = Name.fromString("camelCaseInput") -// assertTrue(Name.toTitleCase(sut) == "CamelCaseInput") -// } -// ), -// suite("Name should be convertible to a camel-case string:")( -// test( -// "When the name was originally constructed from a snake-case string" -// ) { -// val sut = Name.fromString("snake_case_input") -// assertTrue(Name.toCamelCase(sut) == "snakeCaseInput") -// }, -// test( -// "When the name was originally constructed from a camel-case string" -// ) { -// val sut = Name.fromString("camelCaseInput") -// assertTrue(Name.toCamelCase(sut) == "camelCaseInput") -// } -// ), -// suite("Name should be convertible to snake-case")( -// test("When given a name constructed from a list of words") { -// val input = Name.fromList(List("foo", "bar", "baz", "123")) -// assertTrue(Name.toSnakeCase(input) == "foo_bar_baz_123") -// }, -// test("When the name has parts of an abbreviation") { -// val name = Name.fromList(List("value", "in", "u", "s", "d")) -// assertTrue(Name.toSnakeCase(name) == "value_in_USD") -// } -// ), -// suite("Name should be convertible to kebab-case")( -// test("When given a name constructed from a list of words") { -// val input = Name.fromList(List("foo", "bar", "baz", "123")) -// assertTrue(Name.toKebabCase(input) == "foo-bar-baz-123") -// }, -// test("When the name has parts of an abbreviation") { -// val name = Name.fromList(List("value", "in", "u", "s", "d")) -// assertTrue(Name.toKebabCase(name) == "value-in-USD") -// } -// ), -// suite("Name toHumanWords should provide a list of words from a Name")( -// test("When the name is from a camelCase string") { -// val sut = Name.fromString("ValueInUSD") -// assertTrue(Name.toHumanWords(sut) == List("value", "in", "USD")) -// } -// ), -// suite("fromIterable")( -// test("Splits provided names as expected") { -// assertTrue(Name.fromIterable(List("fooBar", "fizzBuzz")) == Name("foo", "bar", "fizz", "buzz")) -// } -// ), -// suite("Misc")( -// test("Name.toString") { -// assertTrue(Name.fromString("fooBar").toString == "[foo,bar]", Name.fromString("a").toString == "[a]") -// } -// ), -// suite("VariableName")( -// test("When calling VariableName.unapply") { -// val sut = Name.fromString("InspectorGadget") -// val variableName = Name.VariableName.unapply(sut) -// assertTrue(variableName == Some("inspectorGadget")) -// }, -// test("When using as an extractor") { -// val sut = Name.fromString("IronMan") -// val actual = sut match { -// case Name.VariableName(variableName) => variableName -// case _ => "not a variable name" -// } -// assertTrue(actual == "ironMan") -// } -// ), -// suite("String Interpolation")( -// test("When using the n interpolator on a plain string") { -// assertTrue(n"Foo" == Name.fromString("Foo"), n"Foo" == Name.fromList(List("foo"))) -// }, -// test("When using the n interpolator with an int value") { -// val n = 42 -// assertTrue(n"Foo$n" == Name.fromString("Foo42"), n"Foo$n" == Name.fromList(List("foo", "42"))) -// } -// ), -// suite("Operators")( -// suite("+")( -// test("It should support adding a String to a Name") { -// assertTrue(Name.fromString("Foo") + "bar" == Name.fromString("FooBar")) -// } -// ) -// ) -// ) -//} +object NameSpec extends MorphirSpecDefault { + def spec = suite("Name")( + suite("Create a Name from a string and check that:")( + suite("Name should be creatable from a single word that:")( + test("Starts with a capital letter") { + assertTrue(Name.fromString("Marco") == Name("marco")) + }, + test("Is all lowercase") { + assertTrue(Name.fromString("polo") == Name("polo")) + } + ), + suite("Name should be creatable from compound words that:")( + test("Are formed from a snake case word") { + assertTrue(Name.fromString("super_mario_world") == Name("super", "mario", "world")) + }, + test("Contain many kinds of word delimiters") { + assertTrue(Name.fromString("fooBar_baz 123") == Name("foo", "bar", "baz", "123")) + }, + test("Are formed from a camel-cased string") { + assertTrue(Name.fromString("valueInUSD") == Name("value", "in", "u", "s", "d")) + }, + test("Are formed from a title-cased string") { + assertTrue( + Name.fromString("ValueInUSD") == Name("value", "in", "u", "s", "d"), + Name.fromString("ValueInJPY") == Name("value", "in", "j", "p", "y") + ) + }, + test("Have a number in the middle") { + assertTrue(Name.fromString("Nintendo64VideoGameSystem") == Name("nintendo", "64", "video", "game", "system")) + }, + test("Are complete and utter nonsense") { + assertTrue(Name.fromString("_-%") == Name.empty) + } + ), + test("It splits the name as expected") { + // "fooBar","blahBlah" => ["foo","bar","blah","blah"] + // "fooBar","blahBlah" => ["fooBar","blahBlah"] + assertTrue( + Name.fromString("fooBar").toList == List("foo", "bar") + ) + } + ), + suite("Name should be convertible to a title-case string:")( + test("When the name was originally constructed from a snake-case string") { + val sut = Name.fromString("snake_case_input") + assertTrue(Name.toTitleCase(sut) == "SnakeCaseInput") + }, + test( + "When the name was originally constructed from a camel-case string" + ) { + val sut = Name.fromString("camelCaseInput") + assertTrue(Name.toTitleCase(sut) == "CamelCaseInput") + } + ), + suite("Name should be convertible to a camel-case string:")( + test( + "When the name was originally constructed from a snake-case string" + ) { + val sut = Name.fromString("snake_case_input") + assertTrue(Name.toCamelCase(sut) == "snakeCaseInput") + }, + test( + "When the name was originally constructed from a camel-case string" + ) { + val sut = Name.fromString("camelCaseInput") + assertTrue(Name.toCamelCase(sut) == "camelCaseInput") + } + ), + suite("Name should be convertible to snake-case")( + test("When given a name constructed from a list of words") { + val input = Name.fromList(List("foo", "bar", "baz", "123")) + assertTrue(Name.toSnakeCase(input) == "foo_bar_baz_123") + }, + test("When the name has parts of an abbreviation") { + val name = Name.fromList(List("value", "in", "u", "s", "d")) + assertTrue(Name.toSnakeCase(name) == "value_in_USD") + } + ), + suite("Name should be convertible to kebab-case")( + test("When given a name constructed from a list of words") { + val input = Name.fromList(List("foo", "bar", "baz", "123")) + assertTrue(Name.toKebabCase(input) == "foo-bar-baz-123") + }, + test("When the name has parts of an abbreviation") { + val name = Name.fromList(List("value", "in", "u", "s", "d")) + assertTrue(Name.toKebabCase(name) == "value-in-USD") + } + ), + suite("Name toHumanWords should provide a list of words from a Name")( + test("When the name is from a camelCase string") { + val sut = Name.fromString("ValueInUSD") + assertTrue(Name.toHumanWords(sut) == List("value", "in", "USD")) + } + ), + suite("fromIterable")( + test("Splits provided names as expected") { + assertTrue(Name.fromIterable(List("fooBar", "fizzBuzz")) == Name("foo", "bar", "fizz", "buzz")) + } + ), + suite("Misc")( + test("Name.toString") { + assertTrue(Name.fromString("fooBar").toString == "[foo,bar]", Name.fromString("a").toString == "[a]") + } + ), + suite("VariableName")( + test("When calling VariableName.unapply") { + val sut = Name.fromString("InspectorGadget") + val variableName = Name.VariableName.unapply(sut) + assertTrue(variableName == Some("inspectorGadget")) + }, + test("When using as an extractor") { + val sut = Name.fromString("IronMan") + val actual = sut match { + case Name.VariableName(variableName) => variableName + case _ => "not a variable name" + } + assertTrue(actual == "ironMan") + } + ), + suite("String Interpolation")( + test("When using the n interpolator on a plain string") { + assertTrue(n"Foo" == Name.fromString("Foo"), n"Foo" == Name.fromList(List("foo"))) + }, + test("When using the n interpolator with an int value") { + val n = 42 + assertTrue(n"Foo$n" == Name.fromString("Foo42"), n"Foo$n" == Name.fromList(List("foo", "42"))) + } + ), + suite("Operators")( + suite("+")( + test("It should support adding a String to a Name") { + assertTrue(Name.fromString("Foo") + "bar" == Name.fromString("FooBar")) + } + ) + ) + ) +} diff --git a/morphir/test/src/org/finos/morphir/ir/gen1/PathSpec.scala b/morphir/test/src/org/finos/morphir/ir/gen1/PathSpec.scala index 5abc98a66..963b844fa 100644 --- a/morphir/test/src/org/finos/morphir/ir/gen1/PathSpec.scala +++ b/morphir/test/src/org/finos/morphir/ir/gen1/PathSpec.scala @@ -1,114 +1,115 @@ package org.finos.morphir.ir.gen1 +import org.finos.morphir.ir.gen1.naming.* import org.finos.morphir.testing.MorphirSpecDefault import zio.test.* -//object PathSpec extends MorphirSpecDefault { -// def spec = suite("Path")( -// suite("Creating a Path from a String")( -// test("It can be constructed from a simple string") { -// assertTrue(Path.fromString("Person") == Path(n"person")) -// }, -// test("It can be constructed from a long string") { -// assertTrue(Path.fromString("She Sells Seashells") == Path(n"she sells seashells")) -// }, -// test("It can be constructed when given a dotted string") { -// assertTrue(Path.fromString("blog.Author") == Path(n"blog", n"author")) -// }, -// test("It can be constructed when given a '-' separated string") { -// assertTrue(Path.fromString("blog-Author") == Path(n"blog", Name.fromList(List("author")))) -// }, -// test("It can be constructed when given a '/' separated string") { -// assertTrue(Path.fromString("blog/Author") == Path(Name.fromList("blog"), Name.fromList("author"))) -// }, -// test("It can be constructed when given a '\' separated string") { -// assertTrue(Path.fromString("blog\\Author") == Path(n"blog", n"author")) -// }, -// test("It can be constructed when given a ':' separated string") { -// assertTrue(Path.fromString("Morphir:SDK") == Path(n"Morphir", n"SDK")) -// }, -// test("It can be constructed when given a ';' separated string") { -// assertTrue(Path.fromString("Blog ; Author") == Path(n"blog", n"author")) -// }, -// test("It can be constructed from Name arguments") { -// assertTrue( -// Path(Name.fromString("projectfiles"), Name.fromString("filePath")) == Path.fromList( -// List(Name.fromList(List("projectfiles")), Name.fromList(List("file", "path"))) -// ) -// ) -// }, -// test("It can be constructed from string arguments") { -// assertTrue( -// Path("myCompany", "some Type") == Path.fromList( -// Name.fromList("my", "company"), -// Name.fromList("some", "type") -// ) -// ) -// } -// ), -// suite("Transforming a Path into a String")( -// test("Paths with period and TitleCase") { -// val input = Path( -// Name("foo", "bar"), -// Name("baz") -// ) -// assertTrue(Path.toString(Name.toTitleCase, ".", input) == "FooBar.Baz") -// }, -// test("Paths with slash and Snake_Case") { -// val input = Path( -// Name("foo", "bar"), -// Name("baz") -// ) -// assertTrue(Path.toString(Name.toSnakeCase, "/", input) == "foo_bar/baz") -// } -// ), -// suite("Transforming a Path into list of Names")( -// test("It can be constructed using toList") { -// assertTrue( -// Path.toList(Path(Name("Com", "Example"), Name("Hello", "World"))) == List( -// Name("Com", "Example"), -// Name("Hello", "World") -// ) -// ) -// } -// ), -// suite("Creating a Path from a Name")( -// test("It can be constructed from names")( -// assertTrue( -// Path.root / Name("Org") / Name("Finos") == Path(Vector(Name("Org"), Name("Finos"))), -// Path.root / Name("Alpha") / Name("Beta") / Name("Gamma") == Path(Vector( -// Name("Alpha"), -// Name("Beta"), -// Name("Gamma") -// )) -// ) -// ) -// ), -// suite("Checking if one Path is a prefix of another should:")( -// test("""Return true: Given path is "foo/bar" and prefix is "foo" """) { -// val sut = Path.fromString("foo/bar") -// val prefix = Path.fromString("foo") -// -// assertTrue(Path.isPrefixOf(prefix = prefix, path = sut)) -// }, -// test("""Return false: Given path is "foo/foo" and prefix is "bar" """) { -// val sut = Path.fromString("foo/foo") -// val prefix = Path.fromString("bar") -// -// assertTrue(!Path.isPrefixOf(prefix = prefix, path = sut)) -// }, -// test("""Return true: Given equal paths""") { -// val sut = Path.fromString("foo/bar/baz") -// val prefix = sut -// assertTrue(Path.isPrefixOf(prefix = prefix, path = sut)) -// } -// ), -// suite("ToString")( -// test("The standard to String should return a String representation of the path using the default PathRenderer")( -// assertTrue( -// Path.fromString("foo/bar/baz").toString == "Foo.Bar.Baz" -// ) -// ) -// ) -// ) -//} +object PathSpec extends MorphirSpecDefault { + def spec = suite("Path")( + suite("Creating a Path from a String")( + test("It can be constructed from a simple string") { + assertTrue(Path.fromString("Person") == Path(n"person")) + }, + test("It can be constructed from a long string") { + assertTrue(Path.fromString("She Sells Seashells") == Path(n"she sells seashells")) + }, + test("It can be constructed when given a dotted string") { + assertTrue(Path.fromString("blog.Author") == Path(n"blog", n"author")) + }, + test("It can be constructed when given a '-' separated string") { + assertTrue(Path.fromString("blog-Author") == Path(n"blog", Name.fromList(List("author")))) + }, + test("It can be constructed when given a '/' separated string") { + assertTrue(Path.fromString("blog/Author") == Path(Name.fromList("blog"), Name.fromList("author"))) + }, + test("It can be constructed when given a '\' separated string") { + assertTrue(Path.fromString("blog\\Author") == Path(n"blog", n"author")) + }, + test("It can be constructed when given a ':' separated string") { + assertTrue(Path.fromString("Morphir:SDK") == Path(n"Morphir", n"SDK")) + }, + test("It can be constructed when given a ';' separated string") { + assertTrue(Path.fromString("Blog ; Author") == Path(n"blog", n"author")) + }, + test("It can be constructed from Name arguments") { + assertTrue( + Path(Name.fromString("projectfiles"), Name.fromString("filePath")) == Path.fromList( + List(Name.fromList(List("projectfiles")), Name.fromList(List("file", "path"))) + ) + ) + }, + test("It can be constructed from string arguments") { + assertTrue( + Path("myCompany", "some Type") == Path.fromList( + Name.fromList("my", "company"), + Name.fromList("some", "type") + ) + ) + } + ), + suite("Transforming a Path into a String")( + test("Paths with period and TitleCase") { + val input = Path( + Name("foo", "bar"), + Name("baz") + ) + assertTrue(Path.toString(Name.toTitleCase, ".", input) == "FooBar.Baz") + }, + test("Paths with slash and Snake_Case") { + val input = Path( + Name("foo", "bar"), + Name("baz") + ) + assertTrue(Path.toString(Name.toSnakeCase, "/", input) == "foo_bar/baz") + } + ), + suite("Transforming a Path into list of Names")( + test("It can be constructed using toList") { + assertTrue( + Path.toList(Path(Name("Com", "Example"), Name("Hello", "World"))) == List( + Name("Com", "Example"), + Name("Hello", "World") + ) + ) + } + ), + suite("Creating a Path from a Name")( + test("It can be constructed from names")( + assertTrue( + Path.root / Name("Org") / Name("Finos") == Path(Vector(Name("Org"), Name("Finos"))), + Path.root / Name("Alpha") / Name("Beta") / Name("Gamma") == Path(Vector( + Name("Alpha"), + Name("Beta"), + Name("Gamma") + )) + ) + ) + ), + suite("Checking if one Path is a prefix of another should:")( + test("""Return true: Given path is "foo/bar" and prefix is "foo" """) { + val sut = Path.fromString("foo/bar") + val prefix = Path.fromString("foo") + + assertTrue(Path.isPrefixOf(prefix = prefix, path = sut)) + }, + test("""Return false: Given path is "foo/foo" and prefix is "bar" """) { + val sut = Path.fromString("foo/foo") + val prefix = Path.fromString("bar") + + assertTrue(!Path.isPrefixOf(prefix = prefix, path = sut)) + }, + test("""Return true: Given equal paths""") { + val sut = Path.fromString("foo/bar/baz") + val prefix = sut + assertTrue(Path.isPrefixOf(prefix = prefix, path = sut)) + } + ), + suite("ToString")( + test("The standard to String should return a String representation of the path using the default PathRenderer")( + assertTrue( + Path.fromString("foo/bar/baz").toString == "Foo.Bar.Baz" + ) + ) + ) + ) +} diff --git a/morphir/test/src/org/finos/morphir/ir/gen1/QNameSpec.scala b/morphir/test/src/org/finos/morphir/ir/gen1/QNameSpec.scala index e60d96b4e..7ab1a96ed 100644 --- a/morphir/test/src/org/finos/morphir/ir/gen1/QNameSpec.scala +++ b/morphir/test/src/org/finos/morphir/ir/gen1/QNameSpec.scala @@ -1,54 +1,55 @@ package org.finos.morphir.ir.gen1 +import org.finos.morphir.ir.gen1.naming.* import org.finos.morphir.testing.MorphirSpecDefault import zio.test.* -//object QNameSpec extends MorphirSpecDefault { -// def spec = suite("QName")( -// suite("Creating a tuple from QName")( -// test("toTuple should provide the Path and Name as a tuple") { -// val path = Path.fromString("ice.cream") -// val name = Name.fromString("float") -// val expected = (path, name) -// assertTrue(QName(path, name).toTuple == expected) -// } -// ), -// suite("Creating a QName")( -// test("Creating a QName with a tuple") { -// val path = Path.fromString("friday") -// val name = Name.fromString("night") -// assertTrue(QName.fromTuple((path, name)) == QName(path, name)) -// }, -// test("Creating a QName from a name") { -// val path = Path.fromString("blog.Author") -// val name = Name.fromString("book") -// assertTrue(QName.fromName(path, name) == QName(path, name)) -// } -// ), -// suite("Fetching values from QName")( -// test("localName and path") { -// val path = Path.fromString("path") -// val name = Name.fromString("name") -// assertTrue( -// QName.getLocalName(QName(path, name)) == name, -// QName.getModulePath(QName(path, name)) == path -// ) -// } -// ), -// suite("QName and Strings")( -// test("Create String from QName") { -// val path = Path.fromString("front.page") -// val name = Name.fromString("dictionary words") -// assertTrue(QName(path, name).toString == "Front.Page:dictionaryWords") -// }, -// test("Create QName from String") { -// val str = "Proper.Path:name" -// assertTrue(QName.fromString(str) == Some(QName(Path.fromString("Proper.Path"), Name.fromString("name")))) -// }, -// test("Provide an invalid String") { -// val str2 = "invalidpathname" -// assertTrue(QName.fromString(str2) == None) -// } -// ) -// ) -//} +object QNameSpec extends MorphirSpecDefault { + def spec = suite("QName")( + suite("Creating a tuple from QName")( + test("toTuple should provide the Path and Name as a tuple") { + val path = Path.fromString("ice.cream") + val name = Name.fromString("float") + val expected = (path, name) + assertTrue(QName(path, name).toTuple == expected) + } + ), + suite("Creating a QName")( + test("Creating a QName with a tuple") { + val path = Path.fromString("friday") + val name = Name.fromString("night") + assertTrue(QName.fromTuple((path, name)) == QName(path, name)) + }, + test("Creating a QName from a name") { + val path = Path.fromString("blog.Author") + val name = Name.fromString("book") + assertTrue(QName.fromName(path, name) == QName(path, name)) + } + ), + suite("Fetching values from QName")( + test("localName and path") { + val path = Path.fromString("path") + val name = Name.fromString("name") + assertTrue( + QName.getLocalName(QName(path, name)) == name, + QName.getModulePath(QName(path, name)) == path + ) + } + ), + suite("QName and Strings")( + test("Create String from QName") { + val path = Path.fromString("front.page") + val name = Name.fromString("dictionary words") + assertTrue(QName(path, name).toString == "Front.Page:dictionaryWords") + }, + test("Create QName from String") { + val str = "Proper.Path:name" + assertTrue(QName.fromString(str) == Some(QName(Path.fromString("Proper.Path"), Name.fromString("name")))) + }, + test("Provide an invalid String") { + val str2 = "invalidpathname" + assertTrue(QName.fromString(str2) == None) + } + ) + ) +}