Implement HtmlCanvas; move some tests to commonTest

pull/498/head
Alinson S. Xavier 7 years ago
parent 7ba7edb7d4
commit 5c402b5400

@ -1 +0,0 @@
org.gradle.parallel=true

@ -19,7 +19,6 @@
package org.isoron.platform.concurrency package org.isoron.platform.concurrency
import java.util.concurrent.*
import kotlin.test.* import kotlin.test.*
class ObservableTest { class ObservableTest {
@ -29,20 +28,19 @@ class ObservableTest {
} }
@Test @Test
fun test() { fun testNotifyListeners() {
val latch = CountDownLatch(1) var wasCalled = false
val listener = object : TestListener { val listener = object : TestListener {
override fun onDataChanged(data: Int) { override fun onDataChanged(data: Int) {
assertEquals(42, data) assertEquals(42, data)
latch.countDown() wasCalled = true
} }
} }
val observable = Observable<TestListener>() val observable = Observable<TestListener>()
observable.addListener(listener) observable.addListener(listener)
observable.notifyListeners { l -> observable.notifyListeners { it.onDataChanged(42) }
l.onDataChanged(42) assertTrue(wasCalled)
}
observable.removeListener(listener)
assertTrue(latch.await(3, TimeUnit.SECONDS))
} }
} }

@ -0,0 +1,71 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker 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 General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.platform.gui
class CanvasTest(val platform: Platform) {
interface Platform {
fun createCanvas(width: Int, height: Int): Canvas
fun writePng(canvas: Canvas, filename: String)
}
fun testDrawing() {
val canvas = platform.createCanvas(500, 400)
canvas.setColor(Color(0x303030))
canvas.fillRect(0.0, 0.0, 500.0, 400.0)
canvas.setColor(Color(0x606060))
canvas.setStrokeWidth(25.0)
canvas.drawRect(100.0, 100.0, 300.0, 200.0)
canvas.setColor(Color(0xFFFF00))
canvas.setStrokeWidth(1.0)
canvas.drawRect(0.0, 0.0, 100.0, 100.0)
canvas.fillCircle(50.0, 50.0, 30.0)
canvas.drawRect(0.0, 100.0, 100.0, 100.0)
canvas.fillArc(50.0, 150.0, 30.0, 90.0, 135.0)
canvas.drawRect(0.0, 200.0, 100.0, 100.0)
canvas.fillArc(50.0, 250.0, 30.0, 90.0, -135.0)
canvas.drawRect(0.0, 300.0, 100.0, 100.0)
canvas.fillArc(50.0, 350.0, 30.0, 45.0, 90.0)
canvas.setColor(Color(0xFF0000))
canvas.setStrokeWidth(2.0)
canvas.drawLine(0.0, 0.0, 500.0, 400.0)
canvas.drawLine(500.0, 0.0, 0.0, 400.0)
canvas.setFont(Font.BOLD)
canvas.setFontSize(50.0)
canvas.setColor(Color(0x00FF00))
canvas.setTextAlign(TextAlign.CENTER)
canvas.drawText("HELLO", 250.0, 100.0)
canvas.setTextAlign(TextAlign.RIGHT)
canvas.drawText("HELLO", 250.0, 150.0)
canvas.setTextAlign(TextAlign.LEFT)
canvas.drawText("HELLO", 250.0, 200.0)
canvas.setFont(Font.FONT_AWESOME)
canvas.drawText(FontAwesome.CHECK, 250.0, 300.0)
platform.writePng(canvas, "CanvasTest.png")
}
}

@ -20,14 +20,12 @@
package org.isoron.uhabits.models package org.isoron.uhabits.models
import org.isoron.platform.time.* import org.isoron.platform.time.*
import org.isoron.uhabits.*
import org.isoron.uhabits.models.Checkmark.Companion.CHECKED_AUTOMATIC import org.isoron.uhabits.models.Checkmark.Companion.CHECKED_AUTOMATIC
import org.isoron.uhabits.models.Checkmark.Companion.CHECKED_MANUAL import org.isoron.uhabits.models.Checkmark.Companion.CHECKED_MANUAL
import org.isoron.uhabits.models.Checkmark.Companion.UNCHECKED import org.isoron.uhabits.models.Checkmark.Companion.UNCHECKED
import org.junit.Test
import kotlin.test.* import kotlin.test.*
class CheckmarkListTest : BaseTest() { class CheckmarkListTest {
private val today = LocalDate(2019, 1, 30) private val today = LocalDate(2019, 1, 30)

@ -0,0 +1,110 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker 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 General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.platform.gui
import org.w3c.dom.*
import kotlin.browser.*
import kotlin.math.*
class HtmlCanvas(val canvas: HTMLCanvasElement) : Canvas {
val ctx = canvas.getContext("2d") as CanvasRenderingContext2D
var fontSize = 12.0
var fontWeight = ""
var fontFamily = "sans-serif"
var align = CanvasTextAlign.CENTER
override fun setColor(color: Color) {
val c = "rgb(${color.red * 255}, ${color.green * 255}, ${color.blue * 255})"
ctx.fillStyle = c;
ctx.strokeStyle = c;
}
override fun drawLine(x1: Double, y1: Double, x2: Double, y2: Double) {
ctx.beginPath()
ctx.moveTo(x1 + 0.5, y1 + 0.5)
ctx.lineTo(x2 + 0.5, y2 + 0.5)
ctx.stroke()
}
override fun drawText(text: String, x: Double, y: Double) {
ctx.font = "${fontWeight} ${fontSize}px ${fontFamily}"
ctx.textAlign = align
ctx.textBaseline = CanvasTextBaseline.MIDDLE
ctx.fillText(text, x, y)
}
override fun fillRect(x: Double, y: Double, width: Double, height: Double) {
ctx.fillRect(x - 0.5, y - 0.5, width + 1.0, height + 1.0)
}
override fun drawRect(x: Double, y: Double, width: Double, height: Double) {
ctx.strokeRect(x - 0.5, y - 0.5, width + 1.0, height + 1.0)
}
override fun getHeight(): Double {
return canvas.height.toDouble()
}
override fun getWidth(): Double {
return canvas.width.toDouble()
}
override fun setFont(font: Font) {
fontWeight = if (font == Font.BOLD) "bold" else ""
fontFamily = if (font == Font.FONT_AWESOME) "FontAwesome" else "sans-serif"
}
override fun setFontSize(size: Double) {
fontSize = size
}
override fun setStrokeWidth(size: Double) {
ctx.lineWidth = size
}
override fun fillArc(centerX: Double,
centerY: Double,
radius: Double,
startAngle: Double,
swipeAngle: Double) {
val from = startAngle / 180 * PI
val to = (startAngle + swipeAngle) / 180 * PI
ctx.beginPath()
ctx.moveTo(centerX, centerY)
ctx.arc(centerX, centerY, radius, -from, -to, swipeAngle >= 0)
ctx.lineTo(centerX, centerY)
ctx.fill()
}
override fun fillCircle(centerX: Double, centerY: Double, radius: Double) {
ctx.beginPath()
ctx.arc(centerX, centerY, radius, 0.0, 2 * PI)
ctx.fill()
}
override fun setTextAlign(align: TextAlign) {
this.align = when(align) {
TextAlign.LEFT -> CanvasTextAlign.LEFT
TextAlign.CENTER -> CanvasTextAlign.CENTER
TextAlign.RIGHT -> CanvasTextAlign.RIGHT
}
}
}

@ -0,0 +1,37 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker 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 General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.platform.gui
import org.w3c.dom.*
class HtmlCanvasTest(val canvas: HTMLCanvasElement) : CanvasTest.Platform {
override fun createCanvas(width: Int, height: Int): Canvas {
return HtmlCanvas(canvas)
}
override fun writePng(canvas: Canvas, filename: String) {
}
fun testDrawing() {
val test = CanvasTest(this)
test.testDrawing()
}
}

@ -23,6 +23,7 @@ import org.isoron.platform.io.*
import java.awt.* import java.awt.*
import java.awt.RenderingHints.* import java.awt.RenderingHints.*
import java.awt.font.* import java.awt.font.*
import java.awt.image.*
import kotlin.math.* import kotlin.math.*
fun createFont(path: String): java.awt.Font { fun createFont(path: String): java.awt.Font {
@ -34,15 +35,16 @@ private val NOTO_REGULAR_FONT = createFont("fonts/NotoSans-Regular.ttf")
private val NOTO_BOLD_FONT = createFont("fonts/NotoSans-Bold.ttf") private val NOTO_BOLD_FONT = createFont("fonts/NotoSans-Bold.ttf")
private val FONT_AWESOME_FONT = createFont("fonts/FontAwesome.ttf") private val FONT_AWESOME_FONT = createFont("fonts/FontAwesome.ttf")
class JavaCanvas(val g2d: Graphics2D, class JavaCanvas(val image: BufferedImage,
val widthPx: Int,
val heightPx: Int,
val pixelScale: Double = 2.0) : Canvas { val pixelScale: Double = 2.0) : Canvas {
private val frc = FontRenderContext(null, true, true) private val frc = FontRenderContext(null, true, true)
private var fontSize = 12.0 private var fontSize = 12.0
private var font = Font.REGULAR private var font = Font.REGULAR
private var textAlign = TextAlign.CENTER private var textAlign = TextAlign.CENTER
val widthPx = image.width
val heightPx = image.height
val g2d = image.createGraphics()
init { init {
g2d.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON); g2d.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);

@ -26,50 +26,19 @@ import java.io.*
import javax.imageio.* import javax.imageio.*
class JavaCanvasTest { class JavaCanvasTest : CanvasTest.Platform {
@Test private val commonTest = CanvasTest(this)
fun testDrawing() {
val image = BufferedImage(500, 400, BufferedImage.TYPE_INT_RGB)
val canvas = JavaCanvas(image.createGraphics(), 500, 400, pixelScale=1.0)
canvas.setColor(Color(0x303030))
canvas.fillRect(0.0, 0.0, 500.0, 400.0)
canvas.setColor(Color(0x606060))
canvas.setStrokeWidth(25.0)
canvas.drawRect(100.0, 100.0, 300.0, 200.0)
canvas.setColor(Color(0xFFFF00))
canvas.setStrokeWidth(1.0)
canvas.drawRect(0.0, 0.0, 100.0, 100.0)
canvas.fillCircle(50.0, 50.0, 30.0)
canvas.drawRect(0.0, 100.0, 100.0, 100.0)
canvas.fillArc(50.0, 150.0, 30.0, 90.0, 135.0)
canvas.drawRect(0.0, 200.0, 100.0, 100.0)
canvas.fillArc(50.0, 250.0, 30.0, 90.0, -135.0)
canvas.drawRect(0.0, 300.0, 100.0, 100.0)
canvas.fillArc(50.0, 350.0, 30.0, 45.0, 90.0)
canvas.setColor(Color(0xFF0000))
canvas.setStrokeWidth(2.0)
canvas.drawLine(0.0, 0.0, 500.0, 400.0)
canvas.drawLine(500.0, 0.0, 0.0, 400.0)
canvas.setFont(Font.BOLD) @Test
canvas.setFontSize(50.0) fun testDrawing() = commonTest.testDrawing()
canvas.setColor(Color(0x00FF00))
canvas.setTextAlign(TextAlign.CENTER)
canvas.drawText("HELLO", 250.0, 100.0)
canvas.setTextAlign(TextAlign.RIGHT)
canvas.drawText("HELLO", 250.0, 150.0)
canvas.setTextAlign(TextAlign.LEFT)
canvas.drawText("HELLO", 250.0, 200.0)
canvas.setFont(Font.FONT_AWESOME) override fun createCanvas(width: Int, height: Int): Canvas {
canvas.drawText(FontAwesome.CHECK, 250.0, 300.0) val image = BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
return JavaCanvas(image, pixelScale=1.0)
}
ImageIO.write(image, "png", File("/tmp/JavaCanvasTest.png")) override fun writePng(canvas: Canvas, filename: String) {
val javaCanvas = canvas as JavaCanvas
ImageIO.write(javaCanvas.image, "png", File("/tmp/JavaCanvasTest.png"))
} }
} }

@ -79,7 +79,7 @@ open class BaseViewTest {
component: Component, component: Component,
threshold: Double = 1e-3) { threshold: Double = 1e-3) {
val actual = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) val actual = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
val canvas = JavaCanvas(actual.createGraphics(), width, height) val canvas = JavaCanvas(actual)
val expectedFile: JavaResourceFile val expectedFile: JavaResourceFile
val actualPath = "/tmp/${expectedPath}" val actualPath = "/tmp/${expectedPath}"

@ -25,8 +25,8 @@ import UIKit
class IosCanvasTest : XCTestCase { class IosCanvasTest : XCTestCase {
func testDraw() { func testDraw() {
UIGraphicsBeginImageContext(CGSize(width: 500, height: 400)) UIGraphicsBeginImageContext(CGSize(width: 500, height: 400))
let canvas = IosCanvas(withBounds: CGRect(x: 0, y: 0, width: 500, height: 400)) let canvas = IosCanvas(withBounds: CGRect(x: 0, y: 0, width: 500, height: 400))
canvas.setColor(color: Color(rgb: 0x303030)) canvas.setColor(color: Color(rgb: 0x303030))
canvas.fillRect(x: 0.0, y: 0.0, width: 500.0, height: 400.0) canvas.fillRect(x: 0.0, y: 0.0, width: 500.0, height: 400.0)

@ -10,12 +10,10 @@ core:
$(test_bundle): test/index.js core $(test_bundle): test/index.js core
mkdir -p build/bundles mkdir -p build/bundles
npx webpack $< --silent --mode production --output $@ npx webpack $< --silent --mode development --target web --output $@
test: $(test_bundle) $(node_modules) test: $(test_bundle) $(node_modules)
mkdir -p build/reports open test/index.html
npx mocha $@ --reporter xunit > build/reports/tests.xml
npx mocha $@
clean: clean:
rm -rf build rm -rf build

@ -2231,6 +2231,11 @@
"readable-stream": "^2.3.6" "readable-stream": "^2.3.6"
} }
}, },
"fontawesome": {
"version": "5.6.3",
"resolved": "https://registry.npmjs.org/fontawesome/-/fontawesome-5.6.3.tgz",
"integrity": "sha512-FCc+CawwsJWWprVEg9X14yI7zI+l9YVAyhzgu70qwGeDn0tLLDH/dVfqgij72g4BBGgLGfK2qnvFGAmYUkhaWg=="
},
"for-in": { "for-in": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",

Binary file not shown.

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<title>Canvas Test</title>
<style>
@font-face {
font-family: "FontAwesome";
src: url(FontAwesome.ttf) format("truetype");
}
</style>
</head>
<body>
<script src="../build/bundles/test.js"></script>
<canvas id="canvas" width=500 height=400></canvas>
<script>
const canvas = document.getElementById('canvas');
const test = new document.coreTest.org.isoron.platform.gui.HtmlCanvasTest(canvas);
test.testDrawing();
</script>
</body>
</html>

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<title>Mocha Tests</title>
<link rel="stylesheet" href="../node_modules/mocha/mocha.css">
</head>
<body>
<div id="mocha"></div>
<script src="../node_modules/mocha/mocha.js"></script>
<script src="../node_modules/chai/chai.js"></script>
<script>mocha.setup('bdd')</script>
<script src="../build/bundles/test.js"></script>
<script>mocha.run();</script>
</body>
</html>

@ -1,2 +1,3 @@
var assert = require('assert'); var assert = require('assert');
var coreTest = require('core_test'); var coreTest = require('core_test');
document.coreTest = coreTest

Loading…
Cancel
Save