added working test casres for groovy style markup builders
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package std.util
|
package std.util
|
||||||
|
|
||||||
import java.util.Map as JMap
|
import java.util.Map as JMap
|
||||||
|
import java.util.Map.Entry as JEntry
|
||||||
|
|
||||||
// Map APIs
|
// Map APIs
|
||||||
|
|
||||||
@@ -12,6 +13,14 @@ val JMap<*,*>.size : Int
|
|||||||
val JMap<*,*>.empty : Boolean
|
val JMap<*,*>.empty : Boolean
|
||||||
get() = isEmpty()
|
get() = isEmpty()
|
||||||
|
|
||||||
|
/** Returns the key of the entry */
|
||||||
|
val <K,V> JEntry<K,V>.key : K
|
||||||
|
get() = getKey()
|
||||||
|
|
||||||
|
/** Returns the value of the entry */
|
||||||
|
val <K,V> JEntry<K,V>.value : V
|
||||||
|
get() = getValue()
|
||||||
|
|
||||||
/** Returns the value for the given key or returns the result of the defaultValue function if there was no entry for the given key */
|
/** Returns the value for the given key or returns the result of the defaultValue function if there was no entry for the given key */
|
||||||
inline fun <K,V> java.util.Map<K,V>.getOrElse(key: K, defaultValue: ()-> V) : V {
|
inline fun <K,V> java.util.Map<K,V>.getOrElse(key: K, defaultValue: ()-> V) : V {
|
||||||
val current = this.get(key)
|
val current = this.get(key)
|
||||||
|
|||||||
@@ -12,9 +12,16 @@ trait Factory<T> {
|
|||||||
fun create() : T
|
fun create() : T
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class Element
|
abstract class Element {
|
||||||
|
abstract fun appendTo(builder: StringBuilder): Unit
|
||||||
|
|
||||||
class TextElement(val text : String) : Element
|
}
|
||||||
|
|
||||||
|
class TextElement(val text : String) : Element {
|
||||||
|
override fun appendTo(builder: StringBuilder) {
|
||||||
|
builder.append(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract class Tag(val name : String) : Element {
|
abstract class Tag(val name : String) : Element {
|
||||||
val children = ArrayList<Element>()
|
val children = ArrayList<Element>()
|
||||||
@@ -22,11 +29,46 @@ abstract class Tag(val name : String) : Element {
|
|||||||
|
|
||||||
protected fun initTag<T : Element>(init : T.()-> Unit) : T
|
protected fun initTag<T : Element>(init : T.()-> Unit) : T
|
||||||
where class object T : Factory<T> {
|
where class object T : Factory<T> {
|
||||||
val tag = T.create()
|
val tag = try {
|
||||||
|
T.create()
|
||||||
|
} catch (e: NullPointerException) {
|
||||||
|
val typeName = javaClass.getName()
|
||||||
|
throw UnsupportedOperationException("No class object create() method for $typeName")
|
||||||
|
}
|
||||||
tag.init()
|
tag.init()
|
||||||
children.add(tag)
|
children.add(tag)
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun appendTo(builder: StringBuilder): Unit {
|
||||||
|
builder.append("<")
|
||||||
|
builder.append(name)
|
||||||
|
if (!attributes.isEmpty()) {
|
||||||
|
for (e in attributes.entrySet()) {
|
||||||
|
if (e != null) {
|
||||||
|
builder.append(" ${e.key}=\"${e.value}\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (children.isEmpty()) {
|
||||||
|
builder.append("/>")
|
||||||
|
} else {
|
||||||
|
builder.append(">")
|
||||||
|
for (c in children) {
|
||||||
|
c.appendTo(builder)
|
||||||
|
}
|
||||||
|
builder.append("<")
|
||||||
|
builder.append(name)
|
||||||
|
builder.append(">")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toString(): String {
|
||||||
|
val builder = StringBuilder()
|
||||||
|
appendTo(builder)
|
||||||
|
return builder.toString().sure()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class TagWithText(name : String) : Tag(name) {
|
abstract class TagWithText(name : String) : Tag(name) {
|
||||||
@@ -53,7 +95,11 @@ class Head() : TagWithText("head") {
|
|||||||
fun title(init : Title.()-> Unit) = initTag(init)
|
fun title(init : Title.()-> Unit) = initTag(init)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Title() : TagWithText("title")
|
class Title() : TagWithText("title") {
|
||||||
|
class object : Factory<Title> {
|
||||||
|
override fun create() = Title()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract class BodyTag(name : String) : TagWithText(name) {
|
abstract class BodyTag(name : String) : TagWithText(name) {
|
||||||
}
|
}
|
||||||
@@ -68,20 +114,38 @@ class Body() : BodyTag("body") {
|
|||||||
fun h1(init : H1.()-> Unit) = initTag(init)
|
fun h1(init : H1.()-> Unit) = initTag(init)
|
||||||
|
|
||||||
fun a(href : String) {
|
fun a(href : String) {
|
||||||
a(href) {}
|
a(href, {})
|
||||||
}
|
}
|
||||||
|
|
||||||
fun a(href : String, init : A.()-> Unit) {
|
fun a(href : String, init : A.()-> Unit) {
|
||||||
val a = initTag(init)
|
val a = initTag(init)
|
||||||
a.href = href
|
a.href = href
|
||||||
|
a.attributes.put("href", href)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class B() : BodyTag("b")
|
class B() : BodyTag("b") {
|
||||||
class P() : BodyTag("p")
|
class object : Factory<B> {
|
||||||
class H1() : BodyTag("h1")
|
override fun create() = B()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class P() : BodyTag("p") {
|
||||||
|
class object : Factory<P> {
|
||||||
|
override fun create() = P()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class H1() : BodyTag("h1") {
|
||||||
|
class object : Factory<H1> {
|
||||||
|
override fun create() = H1()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class A() : BodyTag("a") {
|
class A() : BodyTag("a") {
|
||||||
|
class object : Factory<A> {
|
||||||
|
override fun create() = A()
|
||||||
|
}
|
||||||
|
|
||||||
var href: String? = null
|
var href: String? = null
|
||||||
/*
|
/*
|
||||||
TODO this doesn't compile
|
TODO this doesn't compile
|
||||||
|
|||||||
@@ -8,60 +8,89 @@ import std.util.*
|
|||||||
import std.test.*
|
import std.test.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/*
|
|
||||||
TODO generates compiler error
|
|
||||||
see: http://youtrack.jetbrains.net/issue/KT-866
|
|
||||||
|
|
||||||
val justBody = body {
|
val justBody = body {
|
||||||
+"Hello world"
|
+"Hello world"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun result(args : List<String>) =
|
fun result(args : List<String>) =
|
||||||
html {
|
html {
|
||||||
head {
|
head {
|
||||||
title {+"XML encoding with Kotlin"}
|
title {+"XML encoding with Kotlin"}
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
h1 {+"XML encoding with Kotlin"}
|
h1 {+"XML encoding with Kotlin"}
|
||||||
p {+"this format can be used as an alternative markup to XML"}
|
p {+"this format can be used as an alternative markup to XML"}
|
||||||
|
|
||||||
// an element with attributes and text content
|
// an element with attributes and text content
|
||||||
|
a(href = "http://jetbrains.com/kotlin") {+"Kotlin"}
|
||||||
|
|
||||||
|
// mixed content
|
||||||
|
p {
|
||||||
|
+"This is some"
|
||||||
|
b {+"mixed"}
|
||||||
|
+"text. For more see the"
|
||||||
a(href = "http://jetbrains.com/kotlin") {+"Kotlin"}
|
a(href = "http://jetbrains.com/kotlin") {+"Kotlin"}
|
||||||
|
+"project"
|
||||||
|
}
|
||||||
|
p {+"some text"}
|
||||||
|
|
||||||
// mixed content
|
// content generated by
|
||||||
p {
|
p {
|
||||||
+"This is some"
|
for (arg in args)
|
||||||
b {+"mixed"}
|
+arg
|
||||||
+"text. For more see the"
|
|
||||||
a(href = "http://jetbrains.com/kotlin") {+"Kotlin"}
|
|
||||||
+"project"
|
|
||||||
}
|
|
||||||
p {+"some text"}
|
|
||||||
|
|
||||||
// content generated by
|
|
||||||
p {
|
|
||||||
for (arg in args)
|
|
||||||
+arg
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
}
|
||||||
|
|
||||||
|
/** Create a bad element which doesn't have a class object create() method */
|
||||||
|
class BadElem() : BodyTag("bad") {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a bad body to test out badly defined elements */
|
||||||
|
class BadBody() : BodyTag("badBody") {
|
||||||
|
fun bad(init : BadElem.()-> Unit) = initTag(init)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun badBody(init: BadBody.()-> Unit): BadBody {
|
||||||
|
val elem = BadBody()
|
||||||
|
elem.init()
|
||||||
|
return elem
|
||||||
|
}
|
||||||
|
|
||||||
class TemplateHtmlTest() : TestSupport() {
|
class TemplateHtmlTest() : TestSupport() {
|
||||||
fun testNoneCompileYet() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
TODO: compiler bug
|
|
||||||
see: http://youtrack.jetbrains.net/issue/KT-866
|
|
||||||
|
|
||||||
fun testJustBody() {
|
fun testJustBody() {
|
||||||
println(justBody)
|
assertEquals("<body>Hello world<body>", justBody.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testEmbeddedSimpleBody() {
|
||||||
|
val e = body {
|
||||||
|
+"body with text"
|
||||||
|
}
|
||||||
|
assertEquals("<body>body with text<body>", e.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testEmbeddedBodyWithNestedBold() {
|
||||||
|
val e = body {
|
||||||
|
b{
|
||||||
|
+"this is bold"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertEquals("<body><b>this is bold<b><body>", e.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testEmbeddedBodyWithNestedLinks() {
|
||||||
|
val e = body {
|
||||||
|
a("http://jetbrains.com/kotlin") {
|
||||||
|
+"link text"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertEquals("<body><a href=\"http://jetbrains.com/kotlin\">link text<a><body>", e.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testHtmlFunction() {
|
fun testHtmlFunction() {
|
||||||
val text = result(arrayList("a", "b", "c"))
|
val e = result(arrayList("a", "b", "c"))
|
||||||
println(text)
|
assertEquals("""<html><head><title>XML encoding with Kotlin<title><head><body><h1>XML encoding with Kotlin<h1><p>this format can be used as an alternative markup to XML<p><a href="http://jetbrains.com/kotlin">Kotlin<a><b>mixed<b><a href="http://jetbrains.com/kotlin">Kotlin<a><p>This is sometext. For more see theproject<p><p>some text<p><p>abc<p><body><html>""", e.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testEmbeddedFunction() {
|
fun testEmbeddedFunction() {
|
||||||
@@ -69,11 +98,21 @@ class TemplateHtmlTest() : TestSupport() {
|
|||||||
head {
|
head {
|
||||||
title {+"XML encoding with Kotlin"}
|
title {+"XML encoding with Kotlin"}
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
a("http://jetbrains.com/kotlin")
|
a("http://jetbrains.com/kotlin")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
assertEquals("<html><head><title>XML encoding with Kotlin<title><head><body><a href=\"http://jetbrains.com/kotlin\"/><body><html>", e.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testBadlyDefinedElement() {
|
||||||
|
failsWith<UnsupportedOperationException>{
|
||||||
|
val e = badBody {
|
||||||
|
bad{
|
||||||
|
+"Bad Element Text"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println("bad body: $e")
|
||||||
}
|
}
|
||||||
println(e)
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
@@ -102,6 +102,17 @@ fun fails(block: ()-> Any) {
|
|||||||
block()
|
block()
|
||||||
Assert.fail("Expected an exception to be thrown")
|
Assert.fail("Expected an exception to be thrown")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
println("Caught excepted exception: $e")
|
||||||
|
// OK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T: Exception> failsWith(block: ()-> Any) {
|
||||||
|
try {
|
||||||
|
block()
|
||||||
|
Assert.fail("Expected an exception to be thrown")
|
||||||
|
} catch (e: T) {
|
||||||
|
println("Caught excepted exception: $e")
|
||||||
// OK
|
// OK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user