Skip to content

Commit

Permalink
test sprite set jar loading
Browse files Browse the repository at this point in the history
  • Loading branch information
Knauf authored and chriskn committed Dec 10, 2024
1 parent 1144cc9 commit 85107c8
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 44 deletions.
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
Structurizr C4-PlantUML extension aims to bridge the gap between the [structurizr java library](https://github.com/structurizr/java) and [C4-PlantUML](https://github.com/plantuml-stdlib/C4-PlantUML) by extending the structurizr model and providing an extended C4-PlantUML exporter. It is written in Kotlin.

## Table of contents
* [Examples](#example)
* [Example Diagrams](#example-diagrams)
* [How to use it](#how-to-use-it)
* [Related resources](#related-resources)

## Examples
## Example Diagrams

The following examples diagrams demonstrate the features the Structurizr C4-PlantUML provides:
The following example diagrams demonstrate the features the Structurizr C4-PlantUML provides:

* links, icons and properties for elements and relationships
* external containers
Expand Down Expand Up @@ -172,12 +172,12 @@ containerView.add(externalSchema)
containerView.addDependentSoftwareSystems()
containerView.addAllPeople()

workspace.writeDiagrams(File("diagrams/"))
workspace.writeDiagrams(File("diagrams/"))
}
```
### Dynamic diagrams

As the following example shows, the C4-PlantUML extension provides, in addition to the parallel sequences provided by the Structurizr library, nested numbered parallel sequences for dynamic diagrams.
As the following example shows, in addition to the parallel sequences provided by the Structurizr library, nested numbered parallel sequences for dynamic diagrams are supported.

![Example dynamic diagram](./docs/dynamic_example_nested.png)

Expand Down Expand Up @@ -237,12 +237,12 @@ Dynamic diagrams can also be rendered as sequence diagram by setting the propert

### Deployment diagrams

As the following example demonstrates how to model deployments and create deployment diagrams using the C4-PlantUML extension.
As the following example demonstrates how to model deployments and create deployment diagrams.

![Example deployment diagram](./docs/deployment_example.svg)

```kotlin
val mySystem = model.softwareSystem(
val mySystem = model.softwareSystem(
"System container",
"Example System",
Location.Internal
Expand Down Expand Up @@ -379,7 +379,7 @@ val deploymentView =
deploymentView.addDefaultElements()
```

## How to use it
## How to use it

Structurizr C4-PlantUML extension is available in maven central.

Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ plugins {
}

group = "io.github.chriskn"
version = "0.13.1"
version = "0.13.0"
java.sourceCompatibility = JavaVersion.VERSION_17

repositories {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.github.chriskn.structurizrextension.api.view.sprite.sprites.ImageSprite
import com.github.chriskn.structurizrextension.api.view.sprite.sprites.PlantUmlSprite
import com.github.chriskn.structurizrextension.api.view.sprite.sprites.Sprite
import java.net.URI
import kotlin.io.path.listDirectoryEntries
import kotlin.io.path.toPath
import java.io.BufferedReader
import java.io.InputStreamReader

/**
* Sprite library
Expand All @@ -21,15 +20,25 @@ object SpriteLibrary {

private val spritesByName: MutableMap<String, Sprite> = mutableMapOf()

private val defaultSpriteSetPaths = this.javaClass.getResource(DEFAULT_SPRITES_FOLDER)
?.toURI()
?.toPath()
?.listDirectoryEntries()
.orEmpty()
private val spriteSetNames = listOf(
"aws_stdlib_sprites.json",
"azure_stdlib_sprites.json",
"cloudinsight_stdlib_sprites.json",
"elastic_stdlib_sprites.json",
"gcp_stdlib_sprites.json",
"gilbarbara_image_sprites.json",
"k8s_stdlib_sprites.json",
"logos_stdlib_sprites.json",
"material_stdlib_sprites.json",
"office_stdlib_sprites.json",
"osa_stdlib_sprites.json",
"tupadr3_stdlib_sprites.json",
)

init {
defaultSpriteSetPaths.map { spriteSetPath ->
loadSpriteSet(spriteSetPath.toUri())
spriteSetNames.forEach { spriteSetName ->
val spriteSetPath = DEFAULT_SPRITES_FOLDER + spriteSetName
loadSpriteSet(spriteSetPath)
}
}

Expand Down Expand Up @@ -80,16 +89,22 @@ object SpriteLibrary {
*
* Loads a [SpriteSet] json from the given URL and adds the contained sprites to the library
*
* @param spriteSetJsonUri URI pointing to [SpriteSet] json file
* @param spriteSetPath path pointing to [SpriteSet] json file
* @return the loaded SpriteSet
*/
fun loadSpriteSet(spriteSetJsonUri: URI): SpriteSet {
val spriteSet = jacksonObjectMapper().readValue(spriteSetJsonUri.toURL(), SpriteSet::class.java)
val configuredSprites = spriteSet.sprites.map { sprite ->
configureSprite(sprite, spriteSet)
}.toSet()
addSpritesByName(configuredSprites)
return spriteSet.copy(sprites = configuredSprites)
fun loadSpriteSet(spriteSetPath: String): SpriteSet {
val spriteSetStream = this.javaClass.getResourceAsStream(spriteSetPath)
?: throw IllegalArgumentException("SpriteSet not found under path: $spriteSetPath")
BufferedReader(
InputStreamReader(spriteSetStream, Charsets.UTF_8)
).use { reader ->
val spriteSet = jacksonObjectMapper().readValue(reader.readText(), SpriteSet::class.java)
val configuredSprites = spriteSet.sprites.map { sprite ->
configureSprite(sprite, spriteSet)
}.toSet()
addSpritesByName(configuredSprites)
return spriteSet.copy(sprites = configuredSprites)
}
}

private fun addSpritesByName(sprites: Set<Sprite>) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package com.github.chriskn.structurizrextension.view.sprite.library

import com.fasterxml.jackson.core.JsonParseException
import com.github.chriskn.structurizrextension.api.view.sprite.library.SpriteLibrary
import com.github.chriskn.structurizrextension.api.view.sprite.sprites.ImageSprite
import com.github.chriskn.structurizrextension.api.view.sprite.sprites.OpenIconicSprite
import com.github.chriskn.structurizrextension.api.view.sprite.sprites.PlantUmlSprite
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import java.io.File
import java.io.FileNotFoundException
import java.net.URI

private const val EXISTING_SPRITE_NAME = "logos-DocKer-Icon"

Expand Down Expand Up @@ -58,9 +56,8 @@ class SpriteLibraryTest {
@Test
fun `loadSpriteSet loads minimal test sprite set`() {
val expectedSpriteName = "TestSprite"
val spriteSetPath = this.javaClass.getResource("/input/sprites/minimal_sprite_set.json")!!

val spriteSet = SpriteLibrary.loadSpriteSet(spriteSetPath.toURI())
val spriteSet = SpriteLibrary.loadSpriteSet("/input/sprites/minimal_sprite_set.json")
assertThat(spriteSet.sprites).hasSize(1)

val spriteFromLibrary = SpriteLibrary.spriteByName(expectedSpriteName)
Expand All @@ -81,9 +78,8 @@ class SpriteLibraryTest {
additionalIncludes = setOf("common_include.puml", "<local_include>"),
reference = "test_reference"
)
val spriteSetPath = this.javaClass.getResource("/input/sprites/max_sprite_set.json")!!

val spriteSet = SpriteLibrary.loadSpriteSet(spriteSetPath.toURI())
val spriteSet = SpriteLibrary.loadSpriteSet("/input/sprites/max_sprite_set.json")
val plantUmlSprite = spriteSet.sprites.first { it.name == expectedPlantUmlSprite.name }
val plantUmlSpriteFromLib = SpriteLibrary.spriteByName(expectedPlantUmlSprite.name)
assertThat(plantUmlSprite).isEqualTo(plantUmlSpriteFromLib)
Expand All @@ -98,9 +94,8 @@ class SpriteLibraryTest {
scale = 1.5,
additionalDefinitions = setOf("common_definition", "local_definition_img"),
)
val spriteSetPath = this.javaClass.getResource("/input/sprites/max_sprite_set.json")!!

val spriteSet = SpriteLibrary.loadSpriteSet(spriteSetPath.toURI())
val spriteSet = SpriteLibrary.loadSpriteSet("/input/sprites/max_sprite_set.json")
val imageSprite = spriteSet.sprites.first { it.name == expectedImageSprite.name }
val imageSpriteFromLib = SpriteLibrary.spriteByName(expectedImageSprite.name!!)
assertThat(imageSprite).isEqualTo(imageSpriteFromLib)
Expand All @@ -114,9 +109,8 @@ class SpriteLibraryTest {
color = "#ffffff",
scale = 1.2
)
val spriteSetPath = this.javaClass.getResource("/input/sprites/max_sprite_set.json")!!

val spriteSet = SpriteLibrary.loadSpriteSet(spriteSetPath.toURI())
val spriteSet = SpriteLibrary.loadSpriteSet("/input/sprites/max_sprite_set.json")
val openIconicSprite = spriteSet.sprites.first { it.name == expectedOpenIconicSprite.name }
val openIconicSpriteFromLib = SpriteLibrary.spriteByName(expectedOpenIconicSprite.name)
assertThat(openIconicSprite).isEqualTo(openIconicSpriteFromLib)
Expand All @@ -126,23 +120,22 @@ class SpriteLibraryTest {
@Test
fun `loadSpriteSet returns ImageSprites without name`() {
val sprites = SpriteLibrary.loadSpriteSet(
this.javaClass.getResource("/input/sprites/unnamed_image_sprite_sprite_set.json")!!.toURI()
"/input/sprites/unnamed_image_sprite_sprite_set.json"
)
assertThat(sprites.sprites).hasSize(1)
}

@Test
fun `loadSpriteSet throws Exception when url cant be resolved`() {
// <java.net.ConnectException> vs <java.io.FileNotFoundException> depending on jvm version
assertThrows<Exception> {
SpriteLibrary.loadSpriteSet(URI("http://localhost/not_existing"))
assertThrows<IllegalArgumentException> {
SpriteLibrary.loadSpriteSet("http://localhost/not_existing")
}
}

@Test
fun `loadSpriteSet throws FileNotFoundException when no file exists under path`() {
assertThrows<FileNotFoundException> {
SpriteLibrary.loadSpriteSet(File("/input/sprites/").toURI())
assertThrows<JsonParseException> {
SpriteLibrary.loadSpriteSet("/input/sprites/")
}
}
}

0 comments on commit 85107c8

Please sign in to comment.