├── .tool-versions ├── settings.gradle ├── src ├── main │ ├── resources │ │ └── logback.xml │ └── kotlin │ │ └── com │ │ └── tylerthrailkill │ │ └── helpers │ │ └── prettyprint │ │ └── PrettyPrint.kt └── test │ ├── kotlin │ └── com │ │ └── tylerthrailkill │ │ └── helpers │ │ └── prettyprint │ │ ├── KotestConfig.kt │ │ ├── test.kt │ │ ├── StaticFieldsObjectCyclicReference1.java │ │ ├── InlinePrintTest.kt │ │ ├── StaticFieldsObject.java │ │ ├── NaughtyStringsTest.kt │ │ ├── SmallObjectTest.kt │ │ ├── StaticFieldTest.kt │ │ ├── NullabilityTest.kt │ │ ├── PojoTest.kt │ │ ├── EnumTest.kt │ │ ├── TabTest.kt │ │ ├── Objects.kt │ │ ├── TestSetup.kt │ │ ├── CollectionsTest.kt │ │ ├── MapTest.kt │ │ ├── NestedObjectTest.kt │ │ ├── CycleDetectionTest.kt │ │ ├── MultilineStringTest.kt │ │ └── MassiveObjectTest.kt │ └── resources │ ├── logback-test.xml │ ├── naughty_string_printed.txt │ └── naughty_strings.json ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── .idea ├── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── vcs.xml ├── kotlinScripting.xml ├── encodings.xml ├── misc.xml ├── jarRepositories.xml └── gradle.xml ├── .github ├── dependabot.yml ├── workflows │ ├── update-gradle-wrapper.yml │ ├── linter.yml │ ├── gradle.yml │ └── gradle-publish.yml └── linters │ └── .markdown-lint.yml ├── .gitignore ├── LICENSE.md ├── gradlew.bat ├── README.adoc └── gradlew /.tool-versions: -------------------------------------------------------------------------------- 1 | java openjdk-18 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'pretty-print' 2 | 3 | -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snowe2010/pretty-print/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | systemProp.file.encoding=utf-8 3 | org.gradle.jvmargs=-Dfile.encoding=UTF-8 4 | 5 | ossrh.username=xx 6 | ossrh.password=xx 7 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/kotlinScripting.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gradle" # See documentation for possible values 4 | directory: "/" # Location of package manifests 5 | schedule: 6 | interval: "daily" 7 | assignees: 8 | - "snowe2010" 9 | -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/KotestConfig.kt: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint 2 | 3 | import io.kotest.core.config.AbstractProjectConfig 4 | 5 | //object ProjectConfig : AbstractProjectConfig() { 6 | // override val parallelism = 20 7 | //} 8 | -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/test.kt: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.shouldBe 5 | // 6 | //class FooTest : FunSpec() { 7 | // init { 8 | // List(10000) { it }.forEach { 9 | // test("test $it") { 10 | // 1 shouldBe 1 11 | // } 12 | // } 13 | // } 14 | //} 15 | -------------------------------------------------------------------------------- /.github/workflows/update-gradle-wrapper.yml: -------------------------------------------------------------------------------- 1 | name: Update Gradle Wrapper 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" 6 | 7 | jobs: 8 | update-gradle-wrapper: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v2 13 | 14 | - name: Update Gradle Wrapper 15 | uses: gradle-update/update-gradle-wrapper-action@v1 16 | with: 17 | repo-token: ${{ secrets.GITHUB_TOKEN }} 18 | -------------------------------------------------------------------------------- /src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | pretty_print_debug.log 4 | false 5 | 6 | %-5level - %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/StaticFieldsObjectCyclicReference1.java: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint; 2 | 3 | public class StaticFieldsObjectCyclicReference1 { 4 | public static final StaticFieldsObjectCyclicReference1 BAR; 5 | public StaticFieldsObject n; 6 | 7 | static { 8 | BAR = new StaticFieldsObjectCyclicReference1(StaticFieldsObject.FOO); 9 | } 10 | 11 | public StaticFieldsObjectCyclicReference1(StaticFieldsObject i) { 12 | n = i; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/InlinePrintTest.kt: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint 2 | 3 | import io.kotest.core.spec.style.FreeSpec 4 | 5 | class InlinePrintTest : FreeSpec({ 6 | "pretty printing inline should" - { 7 | "print a test string before pretty printing" - { 8 | prettyPrintInline(TinyObject(1)) mapTo """ 9 | TinyObject( 10 | int = 1 11 | ) 12 | inline wrapper function entered 13 | """ 14 | } 15 | } 16 | }) 17 | -------------------------------------------------------------------------------- /.github/workflows/linter.yml: -------------------------------------------------------------------------------- 1 | name: Linter 2 | 3 | # Run this workflow every time a new commit pushed to your repository 4 | on: push 5 | 6 | jobs: 7 | lint: 8 | name: Lint code base 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v2 14 | 15 | - name: Run Super-Linter 16 | uses: github/super-linter@v3 17 | env: 18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 19 | FILTER_REGEX_EXCLUDE: (.*gradle/.*|.*.github/.*|.*\.txt) 20 | VALIDATE_BASH: false 21 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/StaticFieldsObject.java: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint; 2 | 3 | public class StaticFieldsObject { 4 | public static final StaticFieldsObject FOO; 5 | public static final StaticFieldsObject BAR; 6 | public static final StaticFieldsObject BAZ; 7 | public static final StaticFieldsObject BIZ; 8 | public static final StaticFieldsObject BOOZE; 9 | public int n; 10 | 11 | static { 12 | FOO = new StaticFieldsObject(0); 13 | BAR = new StaticFieldsObject(1); 14 | BAZ = new StaticFieldsObject(2); 15 | BIZ = new StaticFieldsObject(3); 16 | BOOZE = new StaticFieldsObject(4); 17 | } 18 | 19 | public StaticFieldsObject(int i) { 20 | n = i; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/NaughtyStringsTest.kt: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint 2 | 3 | import com.beust.klaxon.Klaxon 4 | import io.kotest.core.spec.style.FreeSpec 5 | 6 | class NaughtyStringsTest : FreeSpec({ 7 | "naughty strings should render correctly" - { 8 | val naughtyString = javaClass.getResource("/naughty_strings.json").readText() 9 | val naughtyList = Klaxon().parseArray(naughtyString)!! 10 | "in list" - { 11 | val expectedString = javaClass.getResource("/naughty_string_printed.txt").readText() 12 | prettyPrint( 13 | naughtyList, 14 | wrappedLineWidth = 1000 15 | ) mapTo expectedString // don't wrap in the naughty strings test, as it can't be generated then. 16 | } 17 | } 18 | }) 19 | -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/SmallObjectTest.kt: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint 2 | 3 | import io.kotest.core.spec.style.FreeSpec 4 | 5 | class SmallObjectTest : FreeSpec({ 6 | "tiny object should" - { 7 | "render" - { 8 | "a single field " - { 9 | prettyPrint(TinyObject(1)) mapTo """ 10 | TinyObject( 11 | int = 1 12 | ) 13 | """ 14 | } 15 | } 16 | } 17 | "small object should" - { 18 | "render " - { 19 | "two fields" - { 20 | prettyPrint(SmallObject("a", 1)) mapTo """ 21 | SmallObject( 22 | field1 = "a" 23 | field2 = 1 24 | ) 25 | """ 26 | } 27 | } 28 | } 29 | }) 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Gradle 2 | 3 | .gradle 4 | /build/ 5 | build/* 6 | 7 | # Ignore Gradle GUI config 8 | gradle-app.setting 9 | 10 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 11 | !gradle-wrapper.jar 12 | 13 | # Cache of project 14 | .gradletasknamecache 15 | 16 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 17 | # gradle/wrapper/gradle-wrapper.properties 18 | 19 | out/ 20 | 21 | ## kotlin 22 | 23 | # Compiled class file 24 | *.class 25 | 26 | # Log file 27 | *.log 28 | 29 | # BlueJ files 30 | *.ctxt 31 | 32 | # Mobile Tools for Java (J2ME) 33 | .mtj.tmp/ 34 | 35 | # Package Files # 36 | *.jar 37 | *.war 38 | *.nar 39 | *.ear 40 | *.zip 41 | *.tar.gz 42 | *.rar 43 | 44 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 45 | hs_err_pid* 46 | 47 | ## Intellij 48 | 49 | .idea/workspace.xml 50 | .idea/tasks.xml -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/StaticFieldTest.kt: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint 2 | 3 | import io.kotest.core.spec.style.FreeSpec 4 | 5 | class StaticFieldTest : FreeSpec({ 6 | "pretty printing lists should" - { 7 | "render a list of strings" - { 8 | val staticFieldsObject = StaticFieldsObject.FOO 9 | prettyPrint(staticFieldsObject) mapTo """ 10 | StaticFieldsObject( 11 | FOO = StaticFieldsObject. 12 | BAR = StaticFieldsObject. 13 | BAZ = StaticFieldsObject. 14 | BIZ = StaticFieldsObject. 15 | BOOZE = StaticFieldsObject. 16 | n = 0 17 | ) 18 | """.trimIndent() 19 | } 20 | } 21 | }) 22 | 23 | -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/NullabilityTest.kt: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint 2 | 3 | import io.kotest.core.spec.style.FreeSpec 4 | 5 | class NullabilityTest : FreeSpec({ 6 | // setup() 7 | 8 | // "pretty printing lists should" - { 9 | // "render a list of strings" - { 10 | // prettyPrint(Unit) mapsTo """ 11 | // [ 12 | // "a", 13 | // "b", 14 | // "c" 15 | // ] 16 | // """ 17 | // } 18 | // } 19 | "pretty printing" - { 20 | "null should work" - { 21 | prettyPrint(null) mapTo """ 22 | null 23 | """ 24 | } 25 | "objects with no fields should work" - { 26 | prettyPrint(EmptyObject()) mapTo """ 27 | EmptyObject( 28 | ) 29 | """ 30 | } 31 | } 32 | }) 33 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2019 Tyler B Thrailkill 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 4 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 5 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 6 | persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 11 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 13 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/PojoTest.kt: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint 2 | 3 | import io.kotest.core.spec.style.FreeSpec 4 | 5 | class PojoTest : FreeSpec({ 6 | "pretty print should print primitives correctly: " - { 7 | "string" - { 8 | prettyPrint("Goodbye, cruel world. Goodbye, cruel lamp.") mapTo """ 9 | "Goodbye, cruel world. Goodbye, cruel lamp." 10 | """ 11 | } 12 | "int" - { 13 | prettyPrint(100) mapTo "100" 14 | } 15 | "boolean" - { 16 | prettyPrint(true) mapTo "true" 17 | } 18 | "double" - { 19 | prettyPrint(1.0) mapTo "1.0" 20 | } 21 | "float" - { 22 | prettyPrint(100f) mapTo "100.0" 23 | } 24 | "char" - { 25 | prettyPrint('a') mapTo "a" 26 | } 27 | } 28 | "pretty print should print other objects correctly: " - { 29 | "string" - { 30 | prettyPrint("Goodbye, cruel world. Goodbye, cruel lamp.") mapTo """ 31 | "Goodbye, cruel world. Goodbye, cruel lamp." 32 | """ 33 | } 34 | } 35 | }) 36 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | name: Kotlin CI 2 | 3 | on: push 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2.3.2 12 | 13 | - name: Cache Gradle packages 14 | uses: actions/cache@v2 15 | with: 16 | path: ~/.gradle/caches 17 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} 18 | restore-keys: ${{ runner.os }}-gradle 19 | 20 | - name: Build with Gradle 21 | run: ./gradlew build 22 | 23 | - name: Publish Snapshots to Repositories 24 | run: gradle publish 25 | env: 26 | GITHUB_USERNAME: ${{ github.actor }} 27 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 28 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} 29 | OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} 30 | BINTRAY_USERNAME: ${{ secrets.BINTRAY_USERNAME }} 31 | BINTRAY_API_KEY: ${{ secrets.BINTRAY_API_KEY }} 32 | 33 | 34 | - name: Bundle the build report 35 | if: failure() 36 | run: find . -type d -name 'reports' | zip -@ -r build-reports.zip 37 | 38 | - name: Upload the build report 39 | if: failure() 40 | uses: actions/upload-artifact@master 41 | with: 42 | name: error-report 43 | path: build-reports.zip 44 | -------------------------------------------------------------------------------- /.github/linters/.markdown-lint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ########################### 3 | ########################### 4 | ## Markdown Linter rules ## 5 | ########################### 6 | ########################### 7 | 8 | # Linter rules doc: 9 | # - https://github.com/DavidAnson/markdownlint 10 | # 11 | # Note: 12 | # To comment out a single error: 13 | # 14 | # any violations you want 15 | # 16 | # 17 | 18 | ############### 19 | # Rules by id # 20 | ############### 21 | MD001: false # want to be able to link to individual sections as part of the api 22 | MD004: false # Unordered list style 23 | MD007: 24 | indent: 2 # Unordered list indentation 25 | MD013: 26 | line_length: 808 # Line length 27 | MD009: false # Trailing spaces are useful 28 | MD026: 29 | punctuation: ".,;:!。,;:" # List of not allowed 30 | MD029: false # Ordered list item prefix 31 | MD033: false # Allow inline HTML 32 | MD036: false # Emphasis used instead of a heading 33 | MD041: false # first line is badges, not heading 34 | 35 | ################# 36 | # Rules by tags # 37 | ################# 38 | blank_lines: false # Error on blank lines 39 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 19 | 23 | 24 | 26 | 27 | -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/EnumTest.kt: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint 2 | 3 | import io.kotest.core.spec.style.FreeSpec 4 | 5 | class EnumTest : FreeSpec({ 6 | "pretty printing enums should" - { 7 | "render all values of the enum" - { 8 | prettyPrint(TestEnum.BOOLEAN) mapTo """TestEnum.BOOLEAN""" 9 | } 10 | "render enum in a list" - { 11 | prettyPrint(listOf(TestEnum.BOOLEAN)) mapTo """ 12 | [ 13 | TestEnum.BOOLEAN 14 | ] 15 | """.trimIndent() 16 | } 17 | "render enum as key in a map" - { 18 | prettyPrint(mapOf(TestEnum.BOOLEAN to "")) mapTo """ 19 | { 20 | TestEnum.BOOLEAN -> "" 21 | } 22 | """ 23 | } 24 | "render enum as value in a map" - { 25 | prettyPrint(mapOf("" to TestEnum.BOOLEAN)) mapTo """ 26 | { 27 | "" -> TestEnum.BOOLEAN 28 | } 29 | """ 30 | } 31 | "render enum in an object" - { 32 | prettyPrint(ObjectWithEnum(TestEnum.BOOLEAN)) mapTo """ 33 | ObjectWithEnum( 34 | enum = TestEnum.BOOLEAN 35 | ) 36 | """ 37 | } 38 | } 39 | }) 40 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/TabTest.kt: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint 2 | 3 | import io.kotest.core.spec.style.FreeSpec 4 | 5 | class TabTest : FreeSpec({ 6 | 7 | "pretty printing an object should" - { 8 | "render a list with 4 spaces for the tab size instead of 2" - { 9 | prettyPrint( 10 | tabSize = 4, 11 | obj = listOf("a", "b", "c") 12 | ) mapTo """ 13 | [ 14 | "a", 15 | "b", 16 | "c" 17 | ] 18 | """ 19 | } 20 | "render a list of lists with 4 spaces for the tab size instead of 2" - { 21 | prettyPrint( 22 | tabSize = 4, 23 | obj = listOf(listOf("a", "b", "c"), listOf("a", "b", "c"), listOf("a", "b", "c")) 24 | ) mapTo """ 25 | [ 26 | [ 27 | "a", 28 | "b", 29 | "c" 30 | ], 31 | [ 32 | "a", 33 | "b", 34 | "c" 35 | ], 36 | [ 37 | "a", 38 | "b", 39 | "c" 40 | ] 41 | ] 42 | """ 43 | } 44 | "render a map with 4 spaces for the tab size instead of 2" - { 45 | prettyPrint( 46 | tabSize = 4, 47 | obj = mapOf(mapOf(1 to 2, 2 to 3) to mapOf(3 to 4, 4 to 5)) 48 | ) mapTo """ 49 | { 50 | { 51 | 1 -> 2, 52 | 2 -> 3 53 | } -> { 54 | 3 -> 4, 55 | 4 -> 5 56 | } 57 | } 58 | """ 59 | } 60 | } 61 | }) 62 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 43 | 44 | -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/Objects.kt: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint 2 | 3 | import java.math.BigDecimal 4 | import java.util.UUID 5 | 6 | // Simple objects 7 | 8 | class EmptyObject 9 | 10 | data class TinyObject(var int: Int) 11 | 12 | data class SmallObject(val field1: String, var field2: Int) 13 | 14 | data class LongString(val longString: String) 15 | // Nested objects 16 | 17 | data class NestedSmallObject(val smallObject: SmallObject) 18 | 19 | data class NestedLargeObject( 20 | val nestedSmallObject: NestedSmallObject, 21 | val smallObject: SmallObject, 22 | val testString: String, 23 | val bigObject: NestedLargeObject? = null 24 | ) 25 | 26 | data class NestedObjectWithCollection( 27 | val coll: List 28 | ) 29 | 30 | data class SinglyLinkedIntList(val n: Int, val next: SinglyLinkedIntList?) 31 | 32 | data class NullableLists( 33 | val col: List? 34 | ) 35 | 36 | // Massive Objects, with every type 37 | 38 | data class MassiveObject( 39 | val astring: String, 40 | val listOfObject: MutableList = mutableListOf() 41 | ) 42 | 43 | data class AValueObject( 44 | val uuid: UUID? = null, 45 | val number: BigDecimal, 46 | val emailAddresses: MutableList = mutableListOf(), 47 | val nestedObjectsListToMap: List>, 48 | val nestedObjectsMapToList: Map> 49 | ) 50 | 51 | data class EmailAddress( 52 | val emailAddress: String 53 | ) { 54 | private val serialVersionUUID = 1L 55 | } 56 | 57 | // cyclical objects 58 | data class SmallCyclicalObject1( 59 | var c: SmallCyclicalObject2? = null 60 | ) 61 | 62 | data class SmallCyclicalObject2( 63 | val c: SmallCyclicalObject1? = null 64 | ) 65 | 66 | data class ObjectContainingObjectWithMap( 67 | var objectWithMap: ObjectWithMap? = null 68 | ) 69 | 70 | data class ObjectWithMap( 71 | val map: MutableMap 72 | ) 73 | 74 | data class ObjectContainingObjectWithList( 75 | var objectWithList: ObjectWithList? = null 76 | ) 77 | 78 | data class ObjectWithList( 79 | val list: MutableList 80 | ) 81 | 82 | enum class TestEnum { 83 | NUMBER, 84 | STRING, 85 | BOOLEAN, 86 | NULL; 87 | 88 | override fun toString(): String = name 89 | } 90 | 91 | data class ObjectWithEnum(val enum: TestEnum) 92 | -------------------------------------------------------------------------------- /.github/workflows/gradle-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a package using Gradle and then publish it to GitHub packages when a release is created 2 | # For more information see: https://github.com/actions/setup-java#publishing-using-gradle 3 | 4 | name: Gradle Publish Release 5 | 6 | on: 7 | release: 8 | types: [published] 9 | 10 | jobs: 11 | 12 | debug: 13 | name: Debug 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Dump env 17 | env: 18 | RELEASE_VERSION: ${{ github.event.release.tag_name }} 19 | run: env | sort 20 | - name: Dump GitHub context 21 | env: 22 | GITHUB_CONTEXT: ${{ toJson(github) }} 23 | run: echo "$GITHUB_CONTEXT" 24 | 25 | build: 26 | 27 | runs-on: ubuntu-latest 28 | 29 | steps: 30 | - uses: actions/checkout@v2 31 | - name: Set up JDK 1.8 32 | uses: actions/setup-java@v1 33 | with: 34 | java-version: 1.8 35 | server-id: github # Value of the distributionManagement/repository/id field of the pom.xml 36 | settings-path: ${{ github.workspace }} # location for the settings.xml file 37 | 38 | - name: Build with Gradle 39 | run: gradle build 40 | env: 41 | # have to set this for no good reason, otherwise RELEASE_VERSION below will not be populated 42 | RELEASE_VERSION: ${{ github.event.release.tag_name }} 43 | 44 | - name: Publish to Repositories 45 | run: gradle publish 46 | env: 47 | RELEASE_VERSION: ${{ github.event.release.tag_name }} 48 | GITHUB_USERNAME: ${{ github.actor }} 49 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 50 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} 51 | OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} 52 | BINTRAY_USERNAME: ${{ secrets.BINTRAY_USERNAME }} 53 | BINTRAY_API_KEY: ${{ secrets.BINTRAY_API_KEY }} 54 | 55 | - name: Upload and Publish Bintray Release 56 | run: gradle bintrayUpload bintrayPublish 57 | env: 58 | RELEASE_VERSION: ${{ github.event.release.tag_name }} 59 | GITHUB_USERNAME: ${{ github.actor }} 60 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 61 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} 62 | OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} 63 | BINTRAY_USERNAME: ${{ secrets.BINTRAY_USERNAME }} 64 | BINTRAY_API_KEY: ${{ secrets.BINTRAY_API_KEY }} 65 | GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} 66 | -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/TestSetup.kt: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint 2 | 3 | import io.kotest.matchers.Matcher 4 | import io.kotest.matchers.MatcherResult 5 | import mu.KotlinLogging 6 | import java.io.ByteArrayOutputStream 7 | import java.io.PrintStream 8 | import kotlin.test.assertEquals 9 | 10 | val logger = KotlinLogging.logger {} 11 | 12 | 13 | /** 14 | * Prints a test string 15 | */ 16 | fun inlineWrapper(obj: Any?, printStream: PrintStream) { 17 | printStream.println("inline wrapper function entered") 18 | } 19 | 20 | /** 21 | * Accepts an `expected` string, and compares it against `this`. Removes leading indents and normalizes newlines 22 | */ 23 | infix fun ByteArrayOutputStream.mapTo(expected: String) { 24 | logger.info { "Actual output: $this" } 25 | logger.info { "Expected output: ${expected.trimIndent()}"} 26 | assertEquals( 27 | expected.trimIndent(), 28 | this.toString().trim().replace("\r", "") 29 | ) 30 | } 31 | 32 | /** 33 | * 34 | * Test helper function, defaults to providing no tab size and wrapping the print stream in 35 | * a ByteArrayOutputStream to test against 36 | */ 37 | fun prettyPrint(obj: Any?, tabSize: Int? = null, wrappedLineWidth: Int? = null): ByteArrayOutputStream { 38 | val outContent = ByteArrayOutputStream() 39 | if (tabSize == null) { 40 | pp(obj, writeTo = PrintStream(outContent), wrappedLineWidth = wrappedLineWidth ?: 80) // TODO fix this, really messy 41 | } else { 42 | pp(obj, indent = tabSize, writeTo = PrintStream(outContent), wrappedLineWidth = wrappedLineWidth ?: 80) // TODO ^ 43 | } 44 | return outContent 45 | } 46 | 47 | /** 48 | * Helper function for testing the inline version of `pp` 49 | * It defaults to providing no tab size and wrapping the print stream in 50 | * a ByteArrayOutputStream to test against 51 | */ 52 | fun prettyPrintInline(obj: Any?, tabSize: Int? = null): ByteArrayOutputStream { 53 | // val outContent by memoized() 54 | val outContent = ByteArrayOutputStream() 55 | val printStream = PrintStream(outContent) 56 | if (tabSize == null) { 57 | inlineWrapper(obj.pp(writeTo = printStream), printStream) 58 | } else { 59 | inlineWrapper(obj.pp(indent = tabSize, writeTo = printStream), printStream) 60 | } 61 | return outContent 62 | } 63 | 64 | fun mapTo(expected: String) = object : Matcher { 65 | override fun test(value: ByteArrayOutputStream) = 66 | MatcherResult( 67 | expected.trimIndent() == value.toString().trim().replace("\r",""), 68 | "$value does not match expected output $expected", 69 | "$value does not match expected output $expected" 70 | ) 71 | } 72 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/CollectionsTest.kt: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint 2 | 3 | import io.kotest.core.spec.style.FreeSpec 4 | 5 | class CollectionsTest : FreeSpec({ 6 | "pretty printing lists should" - { 7 | "render a list of strings" - { 8 | prettyPrint(listOf("a", "b", "c")) mapTo """ 9 | [ 10 | "a", 11 | "b", 12 | "c" 13 | ] 14 | """ 15 | } 16 | "render a list of mixed primitive objects" - { 17 | prettyPrint(listOf("a", 1, true)) mapTo """ 18 | [ 19 | "a", 20 | 1, 21 | true 22 | ] 23 | """ 24 | } 25 | 26 | "render null lists as null" - { 27 | prettyPrint(NullableLists(null)) mapTo """ 28 | NullableLists( 29 | col = null 30 | ) 31 | """ 32 | } 33 | "render lists with null items" - { 34 | prettyPrint(NullableLists(listOf(null, null, null))) mapTo """ 35 | NullableLists( 36 | col = [ 37 | null, 38 | null, 39 | null 40 | ] 41 | ) 42 | """ 43 | } 44 | "render lists with mixed null and not-null items" - { 45 | prettyPrint(NullableLists(listOf(null, 1, null, "a", null, true))) mapTo """ 46 | NullableLists( 47 | col = [ 48 | null, 49 | 1, 50 | null, 51 | "a", 52 | null, 53 | true 54 | ] 55 | ) 56 | """ 57 | } 58 | "render lists with a small object" - { 59 | prettyPrint(NullableLists(listOf(TinyObject(1)))) mapTo """ 60 | NullableLists( 61 | col = [ 62 | TinyObject( 63 | int = 1 64 | ) 65 | ] 66 | ) 67 | """ 68 | } 69 | "render lists with multiple small objects" - { 70 | prettyPrint( 71 | NullableLists( 72 | listOf( 73 | TinyObject(1), 74 | TinyObject(2), 75 | TinyObject(3) 76 | ) 77 | ) 78 | ) mapTo """ 79 | NullableLists( 80 | col = [ 81 | TinyObject( 82 | int = 1 83 | ), 84 | TinyObject( 85 | int = 2 86 | ), 87 | TinyObject( 88 | int = 3 89 | ) 90 | ] 91 | ) 92 | """ 93 | } 94 | "lists with maps" - { 95 | prettyPrint( 96 | NullableLists( 97 | listOf( 98 | mapOf(1 to 2, 3 to 4), 99 | mapOf(5 to 6, 7 to 8), 100 | mapOf(9 to 0, 0 to 1) 101 | ) 102 | ) 103 | ) mapTo """ 104 | NullableLists( 105 | col = [ 106 | { 107 | 1 -> 2, 108 | 3 -> 4 109 | }, 110 | { 111 | 5 -> 6, 112 | 7 -> 8 113 | }, 114 | { 115 | 9 -> 0, 116 | 0 -> 1 117 | } 118 | ] 119 | ) 120 | """ 121 | } 122 | 123 | } 124 | }) 125 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | image:https://img.shields.io/github/workflow/status/snowe2010/pretty-print/Kotlin%20CI[GitHub Workflow Status] 2 | image:https://img.shields.io/bintray/v/snowe/maven/Pretty-Print[Bintray] 3 | image:https://img.shields.io/codecov/c/github/snowe2010/pretty-print[Codecov] 4 | 5 | == pretty-print - pp 6 | 7 | Adds a `pp(Any?)` and `T.pp()` method to pretty print any Java or Kotlin object. 8 | 9 | `pp(Any?)` takes any object and prints it in a pretty format. 10 | 11 | `T.pp()` pretty prints inside a method chain when called on an object inline. 12 | 13 | 14 | [%header,cols="1,3a"] 15 | |=== 16 | |Approach 17 | |Instruction 18 | 19 | |Gradle 20 | |[source,groovy] 21 | ---- 22 | testImplementation "com.tylerthrailkill.helpers:pretty-print:{version}" 23 | ---- 24 | 25 | |Gradle Kotlin DSL 26 | |[source,kotlin] 27 | ---- 28 | testImplementation("com.tylerthrailkill.helpers:pretty-print:$version") 29 | ---- 30 | 31 | |Maven 32 | |[source,xml] 33 | ---- 34 | 35 | com.tylerthrailkill.helpers 36 | pretty-print 37 | {version} 38 | 39 | ---- 40 | |=== 41 | 42 | 43 | == API 44 | 45 | `pp(obj: Any?, indent: Int = 2, writeTo: Appendable = System.out, wrappedLineWidth: Int = 80) 46 | 47 | [%header,cols="1a,3a,1a"] 48 | |=== 49 | |Parameter 50 | |Description 51 | |Default 52 | 53 | |``obj`` 54 | |object to print 55 | | 56 | 57 | |``indent`` 58 | |changes the number of spaces used to indent each level of the output 59 | |``2`` 60 | 61 | |``writeTo`` 62 | |changes the ``Appendable`` you are printing to 63 | |``System.out`` 64 | 65 | |``wrappedLineWidth`` 66 | |changes the number of characters allowed before wrapping in a multiline string 67 | |`80` 68 | |=== 69 | 70 | 71 | == Examples 72 | 73 | === Main API 74 | 75 | 76 | .Top Level Method 77 | [%collapsible] 78 | ==== 79 | [source,kotlin] 80 | ---- 81 | data class TinyObject(var int: Int) 82 | pp(TinyObject(1)) 83 | ---- 84 | 85 | [source,text] 86 | ---- 87 | TinyObject( 88 | int = 1 89 | ) 90 | ---- 91 | ==== 92 | 93 | .Inline method 94 | [%collapsible] 95 | ==== 96 | [source,kotlin] 97 | ---- 98 | data class TinyObject(var int: Int) 99 | fun callSomething(obj: Any?) { 100 | println("inline wrapper function entered") 101 | } 102 | callSomething(TinyObject(1).pp()) 103 | ---- 104 | 105 | [source,text] 106 | ---- 107 | TinyObject( 108 | int = 1 109 | ) 110 | inline wrapper function entered 111 | ---- 112 | ==== 113 | 114 | === Other uses 115 | 116 | .List 117 | [%collapsible] 118 | ==== 119 | [source,kotlin] 120 | ---- 121 | pp(listOf("1", 2, 3.0, true)) 122 | ---- 123 | 124 | [source,text] 125 | ---- 126 | [ 127 | "1", 128 | 2, 129 | 3.0, 130 | true 131 | ] 132 | ---- 133 | ==== 134 | 135 | .Object with list 136 | [%collapsible] 137 | ==== 138 | [source,kotlin] 139 | ---- 140 | data class OL(val list: List) 141 | pp(OL(listOf("1"))) 142 | ---- 143 | 144 | [source,text] 145 | ---- 146 | OL( 147 | list = [ 148 | "1" 149 | ] 150 | ) 151 | ---- 152 | ==== 153 | 154 | .Map 155 | [%collapsible] 156 | ==== 157 | [source,kotlin] 158 | ---- 159 | pp(mapOf("key1" to "value1", "key2" to "value2")) 160 | ---- 161 | 162 | [source,text] 163 | ---- 164 | { 165 | "key1" -> "value1", 166 | "key2" -> "value2" 167 | } 168 | ---- 169 | ==== 170 | 171 | .Object with map 172 | [%collapsible] 173 | ==== 174 | [source,kotlin] 175 | ---- 176 | data class OM(val map: Map) 177 | pp(OM(mapOf(1 to "value", "key" to 1))) 178 | ---- 179 | 180 | [source,text] 181 | ---- 182 | OM( 183 | map = { 184 | 1 -> "value", 185 | "key" -> 1 186 | } 187 | ) 188 | ---- 189 | ==== 190 | 191 | .Multiline strings 192 | [%collapsible] 193 | ==== 194 | [source,kotlin] 195 | ---- 196 | pp("Goodbye, cruel world. Goodbye, cruel lamp.", wrappedLineWidth = 22) 197 | ---- 198 | 199 | [source,kotlin] 200 | ---- 201 | """ 202 | Goodbye, cruel world. 203 | Goodbye, cruel lamp. 204 | """ 205 | ---- 206 | ==== 207 | 208 | .Multiline strings with unicode line breaking 209 | [%collapsible] 210 | ==== 211 | [source,kotlin] 212 | ---- 213 | pp("Goodbye, cruel world. Good­bye, cruel lamp.", wrappedLineWidth = 27) 214 | ---- 215 | 216 | [source,kotlin] 217 | ---- 218 | """ 219 | Goodbye, cruel world. Good­ 220 | bye, cruel lamp. 221 | """ 222 | ---- 223 | 224 | [source,kotlin] 225 | ---- 226 | pp("😍️🥞😍️", wrappedLineWidth = 3) 227 | ---- 228 | 229 | [source,text] 230 | ---- 231 | """ 232 | 😍️ 233 | 🥞 234 | 😍️ 235 | """ 236 | ---- 237 | ==== 238 | 239 | .Multiple fields 240 | [%collapsible] 241 | ==== 242 | [source,kotlin] 243 | ---- 244 | pp(SmallObject("Goodbye, cruel world. Goodbye, cruel lamp.", 1)) 245 | ---- 246 | 247 | [source,kotlin] 248 | ---- 249 | SmallObject( 250 | field1 = "Goodbye, cruel world. Goodbye, cruel lamp." 251 | field2 = 1 252 | ) 253 | ---- 254 | ==== 255 | 256 | .Different indent size 257 | [%collapsible] 258 | ==== 259 | [source,kotlin] 260 | ---- 261 | data class TinyObject(var int: Int) 262 | pp(TinyObject(1), tabSize = 0) 263 | ---- 264 | 265 | [source,text] 266 | ---- 267 | TinyObject( 268 | int = 1 269 | ) 270 | ---- 271 | 272 | [source,kotlin] 273 | ---- 274 | data class TinyObject(var int: Int) 275 | pp(TinyObject(1), tabSize = 10) 276 | ---- 277 | 278 | [source,text] 279 | ---- 280 | TinyObject( 281 | int = 1 282 | ) 283 | ---- 284 | ==== 285 | 286 | .Different output stream 287 | [%collapsible] 288 | ==== 289 | [source,kotlin] 290 | ---- 291 | val stream = ByteArrayOutputStream() 292 | pp(TinyObject(1), printStream = PrintStream(stream)) 293 | println(":::") 294 | print(stream.toString()) 295 | println(":::") 296 | ---- 297 | 298 | [source,text] 299 | ---- 300 | ::: 301 | TinyObject( 302 | int = 1 303 | ) 304 | ::: 305 | ---- 306 | ==== 307 | 308 | .Cyclic references 309 | [%collapsible] 310 | ==== 311 | [source,kotlin] 312 | ---- 313 | data class O1(var c: O2? = null) 314 | data class O2(var c: O1? = null) 315 | val sco1 = O1() 316 | val sco2 = O2(sco1) 317 | sco1.c = sco2 318 | pp(sco1) 319 | ---- 320 | 321 | [source,text] 322 | ---- 323 | O1( 324 | c = O2( 325 | c = cyclic reference detected for 50699452 326 | ) 327 | )[$id=50699452] 328 | ---- 329 | ==== 330 | 331 | == ToDo 332 | 333 | * Test nullability cases 334 | * implement pretty print for `java*` classes 335 | * fix unicode line breaking with icu4j library characters 336 | * multiplatform 337 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/MapTest.kt: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint 2 | 3 | import io.kotest.core.spec.style.FreeSpec 4 | 5 | class MapTest : FreeSpec({ 6 | 7 | "maps" - { 8 | "strings" - { 9 | "single key value pair" - { 10 | prettyPrint(mapOf("key" to "value")) mapTo """ 11 | { 12 | "key" -> "value" 13 | } 14 | """ 15 | } 16 | "render many key value pairs" - { 17 | prettyPrint( 18 | mapOf( 19 | "key1" to "value1", 20 | "key2" to "value2", 21 | "key3" to "value3", 22 | "key4" to "value4" 23 | ) 24 | ) mapTo """ 25 | { 26 | "key1" -> "value1", 27 | "key2" -> "value2", 28 | "key3" -> "value3", 29 | "key4" -> "value4" 30 | } 31 | """ 32 | } 33 | } 34 | 35 | "objects" - { 36 | "single object as value" - { 37 | prettyPrint( 38 | mapOf( 39 | "key1" to SmallObject("field", 1) 40 | ) 41 | ) mapTo """ 42 | { 43 | "key1" -> SmallObject( 44 | field1 = "field" 45 | field2 = 1 46 | ) 47 | } 48 | """ 49 | } 50 | "single object as key" - { 51 | prettyPrint( 52 | mapOf( 53 | SmallObject("field", 1) to "value1" 54 | ) 55 | ) mapTo """ 56 | { 57 | SmallObject( 58 | field1 = "field" 59 | field2 = 1 60 | ) -> "value1" 61 | } 62 | """ 63 | } 64 | "multiple objects" - { 65 | prettyPrint( 66 | mapOf( 67 | "key1" to SmallObject("field", 1), 68 | "key2" to SmallObject("field2", 2) 69 | ) 70 | ) mapTo """ 71 | { 72 | "key1" -> SmallObject( 73 | field1 = "field" 74 | field2 = 1 75 | ), 76 | "key2" -> SmallObject( 77 | field1 = "field2" 78 | field2 = 2 79 | ) 80 | } 81 | """ 82 | } 83 | "map of lists" - { 84 | prettyPrint( 85 | mapOf( 86 | listOf(1, 2, 3) to listOf(4, 5, 6), 87 | listOf(7, 8, 9) to listOf(0, 1, 2) 88 | ) 89 | ) mapTo """ 90 | { 91 | [ 92 | 1, 93 | 2, 94 | 3 95 | ] -> [ 96 | 4, 97 | 5, 98 | 6 99 | ], 100 | [ 101 | 7, 102 | 8, 103 | 9 104 | ] -> [ 105 | 0, 106 | 1, 107 | 2 108 | ] 109 | } 110 | """ 111 | } 112 | "map of maps" - { 113 | prettyPrint( 114 | mapOf( 115 | mapOf(1 to 2, 2 to 3) to mapOf(3 to 4, 4 to 5), 116 | mapOf(6 to 7, 7 to 8) to mapOf(8 to 9, 9 to 0) 117 | ) 118 | ) mapTo """ 119 | { 120 | { 121 | 1 -> 2, 122 | 2 -> 3 123 | } -> { 124 | 3 -> 4, 125 | 4 -> 5 126 | }, 127 | { 128 | 6 -> 7, 129 | 7 -> 8 130 | } -> { 131 | 8 -> 9, 132 | 9 -> 0 133 | } 134 | } 135 | """ 136 | } 137 | } 138 | "null stuff" - { 139 | "null keys" - { 140 | prettyPrint( 141 | mapOf( 142 | null to SmallObject("field", 1) 143 | ) 144 | ) mapTo """ 145 | { 146 | null -> SmallObject( 147 | field1 = "field" 148 | field2 = 1 149 | ) 150 | } 151 | """ 152 | } 153 | "null values" - { 154 | prettyPrint( 155 | mapOf( 156 | "key1" to null 157 | ) 158 | ) mapTo """ 159 | { 160 | "key1" -> null 161 | } 162 | """ 163 | } 164 | "multiple null values" - { 165 | prettyPrint( 166 | mapOf( 167 | "key1" to null, 168 | "key2" to null 169 | ) 170 | ) mapTo """ 171 | { 172 | "key1" -> null, 173 | "key2" -> null 174 | } 175 | """ 176 | } 177 | "null key and null value" - { 178 | prettyPrint( 179 | mapOf( 180 | null to null 181 | ) 182 | ) mapTo """ 183 | { 184 | null -> null 185 | } 186 | """ 187 | } 188 | "null key and null value 2" - { 189 | prettyPrint( 190 | mapOf( 191 | null to SmallObject("field", 1), 192 | "key2" to null 193 | ) 194 | ) mapTo """ 195 | { 196 | null -> SmallObject( 197 | field1 = "field" 198 | field2 = 1 199 | ), 200 | "key2" -> null 201 | } 202 | """ 203 | } 204 | } 205 | } 206 | }) 207 | -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/NestedObjectTest.kt: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint 2 | 3 | import io.kotest.core.spec.style.FreeSpec 4 | 5 | class NestedObjectTest : FreeSpec({ 6 | "small nested object should" - { 7 | "render a single field with multiple subfields" - { 8 | prettyPrint(NestedSmallObject(SmallObject("a", 1))) mapTo """ 9 | NestedSmallObject( 10 | smallObject = SmallObject( 11 | field1 = "a" 12 | field2 = 1 13 | ) 14 | ) 15 | """ 16 | 17 | } 18 | } 19 | 20 | "nested large object should" - { 21 | "render many nested fields" - { 22 | prettyPrint( 23 | NestedLargeObject( 24 | NestedSmallObject(SmallObject("smallObjectField1", 777)), 25 | SmallObject("a field in top level nested large object", 17), 26 | "a test string in NestedLargeObject", 27 | NestedLargeObject( 28 | NestedSmallObject(SmallObject("inner small object field 1", 888)), 29 | SmallObject("field 1 in nested small", 12), 30 | "a test string in NestedLargeObject inner" 31 | ) 32 | ) 33 | ) mapTo """ 34 | NestedLargeObject( 35 | nestedSmallObject = NestedSmallObject( 36 | smallObject = SmallObject( 37 | field1 = "smallObjectField1" 38 | field2 = 777 39 | ) 40 | ) 41 | smallObject = SmallObject( 42 | field1 = "a field in top level nested large object" 43 | field2 = 17 44 | ) 45 | testString = "a test string in NestedLargeObject" 46 | bigObject = NestedLargeObject( 47 | nestedSmallObject = NestedSmallObject( 48 | smallObject = SmallObject( 49 | field1 = "inner small object field 1" 50 | field2 = 888 51 | ) 52 | ) 53 | smallObject = SmallObject( 54 | field1 = "field 1 in nested small" 55 | field2 = 12 56 | ) 57 | testString = "a test string in NestedLargeObject inner" 58 | bigObject = null 59 | ) 60 | ) 61 | """ 62 | } 63 | } 64 | 65 | "nested object with collection should" - { 66 | "render a single item in a collection" - { 67 | prettyPrint( 68 | NestedObjectWithCollection( 69 | listOf(1) 70 | ) 71 | ) mapTo """ 72 | NestedObjectWithCollection( 73 | coll = [ 74 | 1 75 | ] 76 | ) 77 | """ 78 | } 79 | 80 | "render a single string in a collection" - { 81 | prettyPrint( 82 | NestedObjectWithCollection( 83 | listOf("a string with spaces") 84 | ) 85 | ) mapTo """ 86 | NestedObjectWithCollection( 87 | coll = [ 88 | "a string with spaces" 89 | ] 90 | ) 91 | """ 92 | } 93 | 94 | "render multiple objects in a collection, with commas" - { 95 | prettyPrint( 96 | NestedObjectWithCollection( 97 | listOf(1, 2) 98 | ) 99 | ) mapTo """ 100 | NestedObjectWithCollection( 101 | coll = [ 102 | 1, 103 | 2 104 | ] 105 | ) 106 | """ 107 | } 108 | 109 | "render a single nested object in a collection" - { 110 | prettyPrint( 111 | NestedObjectWithCollection( 112 | listOf(NestedSmallObject(SmallObject("a", 1))) 113 | ) 114 | ) mapTo """ 115 | NestedObjectWithCollection( 116 | coll = [ 117 | NestedSmallObject( 118 | smallObject = SmallObject( 119 | field1 = "a" 120 | field2 = 1 121 | ) 122 | ) 123 | ] 124 | ) 125 | """ 126 | } 127 | 128 | "render a multiple nested objects in a collection, with commas" - { 129 | prettyPrint( 130 | NestedObjectWithCollection( 131 | listOf( 132 | NestedSmallObject(SmallObject("a", 1)), 133 | NestedSmallObject(SmallObject("a", 1)), 134 | NestedSmallObject(SmallObject("a", 1)), 135 | NestedSmallObject(SmallObject("a", 1)) 136 | ) 137 | ) 138 | ) mapTo """ 139 | NestedObjectWithCollection( 140 | coll = [ 141 | NestedSmallObject( 142 | smallObject = SmallObject( 143 | field1 = "a" 144 | field2 = 1 145 | ) 146 | ), 147 | NestedSmallObject( 148 | smallObject = SmallObject( 149 | field1 = "a" 150 | field2 = 1 151 | ) 152 | ), 153 | NestedSmallObject( 154 | smallObject = SmallObject( 155 | field1 = "a" 156 | field2 = 1 157 | ) 158 | ), 159 | NestedSmallObject( 160 | smallObject = SmallObject( 161 | field1 = "a" 162 | field2 = 1 163 | ) 164 | ) 165 | ] 166 | ) 167 | """ 168 | } 169 | } 170 | }) 171 | -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/CycleDetectionTest.kt: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint 2 | 3 | import io.kotest.core.spec.style.FreeSpec 4 | 5 | class CycleDetectionTest : FreeSpec({ 6 | "pretty printing" - { 7 | "plain objects with cycles" - { 8 | "should detect a cycle with plain Unit" - { 9 | val unit = Unit 10 | prettyPrint(unit) mapTo """ 11 | Unit( 12 | INSTANCE = Unit. 13 | ) 14 | """ 15 | } 16 | "should detect a cycle with two small objects" - { 17 | val sco1 = SmallCyclicalObject1() 18 | val sco2 = SmallCyclicalObject2(sco1) 19 | sco1.c = sco2 20 | val identity = System.identityHashCode(sco1) 21 | prettyPrint(sco1) mapTo """ 22 | SmallCyclicalObject1( 23 | c = SmallCyclicalObject2( 24 | c = cyclic reference detected for $identity 25 | ) 26 | )[${'$'}id=$identity] 27 | """ 28 | } 29 | "should detect no cycle when an element is repeated several times in the same objects fields" - { 30 | val smallObject = SmallObject("a string in small object", 777) 31 | val nestedLargeObjectNull = NestedLargeObject( 32 | NestedSmallObject(smallObject), 33 | smallObject, 34 | "test string, please don't break", 35 | null 36 | ) 37 | prettyPrint(nestedLargeObjectNull) mapTo """ 38 | NestedLargeObject( 39 | nestedSmallObject = NestedSmallObject( 40 | smallObject = SmallObject( 41 | field1 = "a string in small object" 42 | field2 = 777 43 | ) 44 | ) 45 | smallObject = SmallObject( 46 | field1 = "a string in small object" 47 | field2 = 777 48 | ) 49 | testString = "test string, please don't break" 50 | bigObject = null 51 | ) 52 | """ 53 | } 54 | } 55 | "maps with cycles" - { 56 | "should detect a cycle between an object with a map with an object with a cycle" - { 57 | val objectWithMap = ObjectWithMap( 58 | mutableMapOf(1 to null) 59 | ) 60 | val objectContainingObjectWithMap = ObjectContainingObjectWithMap() 61 | objectContainingObjectWithMap.objectWithMap = objectWithMap 62 | objectWithMap.map[1] = objectContainingObjectWithMap 63 | val identity = System.identityHashCode(objectWithMap) 64 | prettyPrint(objectWithMap) mapTo """ 65 | ObjectWithMap( 66 | map = { 67 | 1 -> ObjectContainingObjectWithMap( 68 | objectWithMap = cyclic reference detected for $identity 69 | ) 70 | } 71 | )[${'$'}id=$identity] 72 | """.trimIndent() 73 | } 74 | "should detect a cycle of a map containing itself" - { 75 | val outerMap: MutableMap = mutableMapOf(1 to null) 76 | val innerMap = mutableMapOf(1 to outerMap) 77 | outerMap[1] = innerMap 78 | val identity = System.identityHashCode(outerMap) 79 | prettyPrint(outerMap) mapTo """ 80 | { 81 | 1 -> { 82 | 1 -> cyclic reference detected for $identity 83 | } 84 | }[${'$'}id=$identity] 85 | """.trimIndent() 86 | } 87 | } 88 | "lists with cycles" - { 89 | "should detect a cycle between an object with a list with an object with a cycle" - { 90 | val objectWithList = ObjectWithList(mutableListOf()) 91 | val objectContainingObjectWithList = ObjectContainingObjectWithList() 92 | objectContainingObjectWithList.objectWithList = objectWithList 93 | objectWithList.list.add(objectContainingObjectWithList) 94 | val identity = System.identityHashCode(objectWithList) 95 | prettyPrint(objectWithList) mapTo """ 96 | ObjectWithList( 97 | list = [ 98 | ObjectContainingObjectWithList( 99 | objectWithList = cyclic reference detected for $identity 100 | ) 101 | ] 102 | )[${'$'}id=$identity] 103 | """.trimIndent() 104 | } 105 | "should detect a cycle of a list containing itself" - { 106 | val outerList: MutableList = mutableListOf() 107 | val innerList = mutableListOf(outerList) 108 | outerList.add(innerList) 109 | val identity = System.identityHashCode(outerList) 110 | prettyPrint(outerList) mapTo """ 111 | [ 112 | [ 113 | cyclic reference detected for $identity 114 | ] 115 | ][${'$'}id=$identity] 116 | """.trimIndent() 117 | } 118 | } 119 | "a cycle of 3 objects" - { 120 | "a list contains 2 of these objects" - { 121 | "should only show ID of outermost object in the cycle each time the cycle gets printed" - { 122 | // outermost meaning the first object in the cycle that pretty print calls on 123 | val anyMap = { mutableMapOf() } 124 | val a = anyMap() 125 | val b = anyMap() 126 | val c = anyMap() 127 | 128 | a["foo"] = b 129 | b["fie"] = c 130 | c["fum"] = a 131 | 132 | prettyPrint(listOf(a, b)) mapTo """ 133 | [ 134 | { 135 | "foo" -> { 136 | "fie" -> { 137 | "fum" -> cyclic reference detected for ${System.identityHashCode(a)} 138 | } 139 | } 140 | }[${'$'}id=${System.identityHashCode(a)}], 141 | { 142 | "fie" -> { 143 | "fum" -> { 144 | "foo" -> cyclic reference detected for ${System.identityHashCode(b)} 145 | } 146 | } 147 | }[${'$'}id=${System.identityHashCode(b)}] 148 | ] 149 | """.trimIndent() 150 | } 151 | } 152 | } 153 | } 154 | }) 155 | -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/MultilineStringTest.kt: -------------------------------------------------------------------------------- 1 | //@formatter:off 2 | package com.tylerthrailkill.helpers.prettyprint 3 | 4 | import io.kotest.core.spec.style.DescribeSpec 5 | 6 | // TODO add these tests back when you figure out why https://stackoverflow.com/questions/54756894/breakiterator-failing-on-unicode-ucd-linebreaktest 7 | // is happening 8 | val testsToSkipCurrently = listOf( 9 | " × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3]", 10 | " × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3]", 11 | " × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3]", 12 | " × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3]", 13 | " × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] (XX_AL) ÷ [0.3]", 14 | " × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] (XX_AL) ÷ [0.3]", 15 | " × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3]", 16 | " × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3]" 17 | ) 18 | 19 | const val SPACE = ' ' 20 | 21 | class MultilineStringTest : DescribeSpec({ 22 | 23 | describe("really long string reformatting") { 24 | it("when there are plain spaces") { 25 | prettyPrint( 26 | wrappedLineWidth = 22, 27 | obj = SmallObject("Goodbye, cruel world. Goodbye, cruel lamp.", 1) 28 | ) mapTo """ 29 | SmallObject( 30 | field1 = ""${'"'} 31 | Goodbye, cruel world.$SPACE 32 | Goodbye, cruel lamp. 33 | ""${'"'} 34 | field2 = 1 35 | ) 36 | """ 37 | } 38 | 39 | context("when the long string is not part of another object") { 40 | it("renders as a multiline string") { 41 | val s = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa a" 42 | prettyPrint(s) mapTo """ 43 | ${"\"\"\""} 44 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa$SPACE 45 | a 46 | ${"\"\"\""} 47 | """ 48 | } 49 | } 50 | 51 | context("when the long string is the value of a field") { 52 | it("renders as a multiline string") { 53 | prettyPrint( 54 | SmallObject( 55 | "Yes, if you make it look like an electrical fire. When you do things right, people won't be sure you've done anything at all. Too much work. Let's burn it and say we dumped it in the sewer. Goodbye, cruel world. Goodbye, cruel lamp.", 56 | 1 57 | ) 58 | ) mapTo """ 59 | SmallObject( 60 | field1 = ${"\"\"\""} 61 | Yes, if you make it look like an electrical fire. When you do things right,$SPACE 62 | people won't be sure you've done anything at all. Too much work. Let's burn it$SPACE 63 | and say we dumped it in the sewer. Goodbye, cruel world. Goodbye, cruel lamp. 64 | ${"\"\"\""} 65 | field2 = 1 66 | ) 67 | """ 68 | } 69 | } 70 | 71 | context("break should occur between ") { 72 | javaClass.getResource("/LineBreakTest.txt") 73 | .readText() 74 | .lines() 75 | .forEach nextTest@{ testLine -> 76 | if (testLine.startsWith('#') or testLine.isBlank()) { 77 | return@nextTest 78 | } 79 | val parts = mapUnicodeTestLineToParts(testLine) 80 | val padding = " " 81 | val testName = testLine.split('#')[1] 82 | if (testsToSkipCurrently.contains(testName)) { 83 | return@nextTest 84 | } 85 | it(testName) { 86 | logger.info { testName } 87 | logger.debug { parts } 88 | prettyPrint( 89 | wrappedLineWidth = 1, 90 | obj = LongString(parts.flatten().joinToString("")) 91 | ) mapTo """ 92 | LongString( 93 | longString = ""${'"'} 94 | ${parts.joinToString("\n$padding") { it.joinToString("") }} 95 | ""${'"'} 96 | ) 97 | """ 98 | } 99 | } 100 | } 101 | it("when there are unicode breaking space characters at the break point") { 102 | prettyPrint( 103 | wrappedLineWidth = 22, 104 | obj = SmallObject("Goodbye, cruel world.\u1680Goodbye, cruel lamp.", 1) 105 | ) mapTo """ 106 | SmallObject( 107 | field1 = ""${'"'} 108 | Goodbye, cruel world.  109 | Goodbye, cruel lamp. 110 | ""${'"'} 111 | field2 = 1 112 | ) 113 | """ 114 | } 115 | context("in a list") { 116 | it("with plain spaces") { 117 | prettyPrint( 118 | wrappedLineWidth = 22, 119 | obj = listOf("Goodbye, cruel world. Goodbye, cruel lamp.") 120 | ) mapTo """ 121 | [ 122 | ""${'"'} 123 | Goodbye, cruel world. 124 | Goodbye, cruel lamp. 125 | ""${'"'} 126 | ] 127 | """ 128 | } 129 | 130 | it("renders as a multiline string") { 131 | prettyPrint( 132 | listOf( 133 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa a" 134 | ) 135 | ) mapTo """ 136 | [ 137 | ${"\"\"\""} 138 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa$SPACE 139 | a 140 | ${"\"\"\""} 141 | ] 142 | """ 143 | } 144 | } 145 | context("in a map") { 146 | it("as a value with plain spaces") { 147 | prettyPrint( 148 | wrappedLineWidth = 22, 149 | obj = mapOf(1 to "Goodbye, cruel world. Goodbye, cruel lamp.") 150 | ) mapTo """ 151 | { 152 | 1 -> ""${'"'} 153 | Goodbye, cruel world. 154 | Goodbye, cruel lamp. 155 | ""${'"'} 156 | } 157 | """ 158 | } 159 | it("as a key with plain spaces") { 160 | prettyPrint( 161 | wrappedLineWidth = 22, 162 | obj = mapOf("Goodbye, cruel world. Goodbye, cruel lamp." to 1) 163 | ) mapTo """ 164 | { 165 | ""${'"'} 166 | Goodbye, cruel world. 167 | Goodbye, cruel lamp. 168 | ""${'"'} -> 1 169 | } 170 | """ 171 | } 172 | it("renders as a multiline string") { 173 | prettyPrint( 174 | mapOf( 175 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa a" 176 | to "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb b" 177 | ) 178 | ) mapTo """ 179 | { 180 | ${"\"\"\""} 181 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa$SPACE 182 | a 183 | ${"\"\"\""} -> ${"\"\"\""} 184 | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb$SPACE 185 | b 186 | ${"\"\"\""} 187 | } 188 | """ 189 | } 190 | } 191 | } 192 | }) 193 | 194 | private fun mapUnicodeTestLineToParts(testLine: String): List> { 195 | return testLine.replaceAfter(' ', "") 196 | .replace(" ", "") 197 | .replace(" ", "") 198 | .removeSurrounding("×", "÷") 199 | .split('÷') 200 | .map { part -> part.split('×') } 201 | .map { mapOfCodePoints -> 202 | mapOfCodePoints.map { codePoint -> 203 | Integer.parseInt(codePoint, 16) // parse int as hexadecimal 204 | } 205 | } 206 | .map { breakParts -> 207 | breakParts.map { codePoint -> 208 | StringBuilder().appendCodePoint(codePoint).toString() 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /src/main/kotlin/com/tylerthrailkill/helpers/prettyprint/PrettyPrint.kt: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint 2 | 3 | import com.ibm.icu.text.BreakIterator 4 | import mu.KLogging 5 | import java.lang.reflect.Modifier 6 | import java.math.BigDecimal 7 | import java.math.BigInteger 8 | import java.util.* 9 | 10 | /** 11 | * Pretty print function. 12 | * 13 | * Prints any object in a pretty format for easy debugging/reading 14 | * 15 | * @param [obj] the object to pretty print 16 | * @param [indent] optional param that specifies the number of spaces to use to indent. Defaults to 2. 17 | * @param [writeTo] optional param that specifies the [Appendable] to output the pretty print to. Defaults appending to `System.out`. 18 | * @param [wrappedLineWidth] optional param that specifies how many characters of a string should be on a line. 19 | */ 20 | @JvmOverloads 21 | fun pp(obj: Any?, indent: Int = 2, writeTo: Appendable = System.out, wrappedLineWidth: Int = 80) = 22 | PrettyPrinter(indent, writeTo, wrappedLineWidth).pp(obj) 23 | 24 | /** 25 | * Inline helper method for printing withing method chains. Simply delegates to [pp] 26 | * 27 | * Example: 28 | * val foo = op2(op1(bar).pp()) 29 | * 30 | * @param [T] the object to pretty print 31 | * @param [indent] optional param that specifies the number of spaces to use to indent. Defaults to 2. 32 | * @param [writeTo] optional param that specifies the [Appendable] to output the pretty print to. Defaults appending to `System.out` 33 | * @param [wrappedLineWidth] optional param that specifies how many characters of a string should be on a line. 34 | */ 35 | @JvmOverloads 36 | fun T.pp( 37 | indent: Int = 2, 38 | writeTo: Appendable = System.out, 39 | wrappedLineWidth: Int = 80 40 | ): T = this.also { pp(it, indent, writeTo, wrappedLineWidth) } 41 | 42 | /** 43 | * Class for performing pretty print operations on any object with customized indentation, target output, and line wrapping 44 | * width for long strings. 45 | * 46 | * @param [tabSize] How much more to indent each level of nesting. 47 | * @param [writeTo] Where to write a pretty printed object. 48 | * @param [wrappedLineWidth] How long a String needs to be before it gets transformed into a multiline String. 49 | */ 50 | private class PrettyPrinter( 51 | private val tabSize: Int, 52 | private val writeTo: Appendable, 53 | private val wrappedLineWidth: Int 54 | ) { 55 | private val lineInstance = BreakIterator.getLineInstance() 56 | 57 | // private val logger = KotlinLogging.logger {} 58 | private val visited = mutableSetOf() 59 | private val revisited = mutableSetOf() 60 | 61 | companion object : KLogging() 62 | 63 | /** 64 | * Pretty prints the given object with this printer. 65 | * 66 | * @param [obj] The object to pretty print. 67 | */ 68 | fun pp(obj: Any?) { 69 | ppAny(obj) 70 | writeLine() 71 | } 72 | 73 | /** 74 | * The core pretty print method. Delegates to the appropriate pretty print method based on the object's type. Handles 75 | * cyclic references. `collectionElementPad` and `objectFieldPad` are generally the same. A specific case in which they 76 | * differ is to handle the difference in alignment of different types of fields in an object, as seen in `ppPlainObject(...)`. 77 | * 78 | * @param [obj] The object to pretty print. 79 | * @param [collectionElementPad] How much to indent the elements of a collection. 80 | * @param [objectFieldPad] How much to indent the field of an object. 81 | */ 82 | private fun ppAny( 83 | obj: Any?, 84 | collectionElementPad: String = "", 85 | objectFieldPad: String = collectionElementPad, 86 | staticMatchesParent: Boolean = false 87 | ) { 88 | val id = System.identityHashCode(obj) 89 | 90 | if (obj != null && staticMatchesParent) { 91 | val className = obj.javaClass.simpleName 92 | write("$className.") 93 | return 94 | } 95 | 96 | if (!obj.isAtomic() && visited[id]) { 97 | write("cyclic reference detected for $id") 98 | revisited.add(id) 99 | return 100 | } 101 | 102 | visited.add(id) 103 | when { 104 | obj is Iterable<*> -> ppIterable(obj, collectionElementPad) 105 | obj is Map<*, *> -> ppMap(obj, collectionElementPad) 106 | obj is String -> ppString(obj, collectionElementPad) 107 | obj is Enum<*> -> ppEnum(obj) 108 | obj.isAtomic() -> ppAtomic(obj) 109 | obj is Any -> ppPlainObject(obj, objectFieldPad) 110 | } 111 | visited.remove(id) 112 | 113 | if (revisited[id]) { 114 | write("[\$id=$id]") 115 | revisited -= id 116 | } 117 | } 118 | 119 | /** 120 | * Pretty prints the contents of the Iterable receiver. The given function is applied to each element. The result 121 | * of an application to each element is on its own line, separated by a separator. `currentDepth` specifies the 122 | * indentation level of any closing bracket. 123 | */ 124 | private fun Iterable.ppContents(currentDepth: String, separator: String = "", f: (T) -> Unit) { 125 | val list = this.toList() 126 | 127 | if (!list.isEmpty()) { 128 | f(list.first()) 129 | list.drop(1).forEach { 130 | writeLine(separator) 131 | f(it) 132 | } 133 | writeLine() 134 | } 135 | 136 | write(currentDepth) 137 | } 138 | 139 | private fun ppPlainObject(obj: Any, currentDepth: String) { 140 | val increasedDepth = deepen(currentDepth) 141 | val className = obj.javaClass.simpleName 142 | 143 | writeLine("$className(") 144 | obj.javaClass.declaredFields 145 | .filterNot { it.isSynthetic } 146 | .ppContents(currentDepth) { 147 | val staticMatchesParent = Modifier.isStatic(it.modifiers) && it.type == obj.javaClass 148 | 149 | it.isAccessible = true 150 | write("$increasedDepth${it.name} = ") 151 | val extraIncreasedDepth = deepen(increasedDepth, it.name.length + 3) // 3 is " = ".length in prev line 152 | val fieldValue = it.get(obj) 153 | logger.debug { "field value is ${fieldValue.javaClass}" } 154 | ppAny(fieldValue, extraIncreasedDepth, increasedDepth, staticMatchesParent) 155 | } 156 | write(')') 157 | } 158 | 159 | private fun ppIterable(obj: Iterable<*>, currentDepth: String) { 160 | val increasedDepth = deepen(currentDepth) 161 | 162 | writeLine('[') 163 | obj.ppContents(currentDepth, ",") { 164 | write(increasedDepth) 165 | ppAny(it, increasedDepth) 166 | } 167 | write(']') 168 | } 169 | 170 | private fun ppMap(obj: Map<*, *>, currentDepth: String) { 171 | val increasedDepth = deepen(currentDepth) 172 | 173 | writeLine('{') 174 | obj.entries.ppContents(currentDepth, ",") { 175 | write(increasedDepth) 176 | ppAny(it.key, increasedDepth) 177 | write(" -> ") 178 | ppAny(it.value, increasedDepth) 179 | } 180 | write('}') 181 | } 182 | 183 | private fun ppString(s: String, currentDepth: String) { 184 | if (s.length > wrappedLineWidth) { 185 | val tripleDoubleQuotes = "\"\"\"" 186 | writeLine(tripleDoubleQuotes) 187 | writeLine(wordWrap(s, currentDepth)) 188 | write("$currentDepth$tripleDoubleQuotes") 189 | } else { 190 | write("\"$s\"") 191 | } 192 | } 193 | 194 | private fun ppEnum(enum: Enum<*>) { 195 | write("${enum.javaClass.simpleName}.${enum.toString()}") 196 | } 197 | 198 | private fun ppAtomic(obj: Any?) { 199 | write(obj.toString()) 200 | } 201 | 202 | /** 203 | * Writes to the writeTo with a new line and adds logging 204 | */ 205 | private fun writeLine(str: Any? = "") { 206 | logger.debug { "writing $str" } 207 | writeTo.append(str.toString()).appendLine() 208 | } 209 | 210 | /** 211 | * Writes to the writeTo and adds logging 212 | */ 213 | private fun write(str: Any?) { 214 | logger.debug { "writing $str" } 215 | writeTo.append(str.toString()) 216 | } 217 | 218 | private fun wordWrap(text: String, padding: String): String { 219 | lineInstance.setText(text) 220 | var start = lineInstance.first() 221 | var end = lineInstance.next() 222 | val breakableLocations = mutableListOf() 223 | while (end != BreakIterator.DONE) { 224 | val substring = text.substring(start, end) 225 | breakableLocations.add(substring) 226 | start = end 227 | end = lineInstance.next() 228 | } 229 | val arr = mutableListOf(mutableListOf()) 230 | var index = 0 231 | arr[index].add(breakableLocations[0]) 232 | breakableLocations.drop(1).forEach { 233 | val currentSize = arr[index].joinToString(separator = "").length 234 | if (currentSize + it.length <= wrappedLineWidth) { 235 | arr[index].add(it) 236 | } else { 237 | arr.add(mutableListOf(it)) 238 | index += 1 239 | } 240 | } 241 | return arr.flatMap { listOf("$padding${it.joinToString(separator = "")}") }.joinToString("\n") 242 | } 243 | 244 | private fun deepen(currentDepth: String, size: Int = tabSize): String = " ".repeat(size) + currentDepth 245 | } 246 | 247 | /** 248 | * Determines if this object should not be broken down further for pretty printing. 249 | */ 250 | private fun Any?.isAtomic(): Boolean = 251 | this == null 252 | || this is Char || this is Number || this is Boolean || this is BigInteger || this is BigDecimal || this is UUID 253 | 254 | // For syntactic sugar 255 | operator fun Set.get(x: T): Boolean = this.contains(x) 256 | -------------------------------------------------------------------------------- /src/test/resources/naughty_string_printed.txt: -------------------------------------------------------------------------------- 1 | [ 2 | "", 3 | "undefined", 4 | "undef", 5 | "null", 6 | "NULL", 7 | "(null)", 8 | "nil", 9 | "NIL", 10 | "true", 11 | "false", 12 | "True", 13 | "False", 14 | "TRUE", 15 | "FALSE", 16 | "None", 17 | "hasOwnProperty", 18 | "\", 19 | "\\", 20 | "0", 21 | "1", 22 | "1.00", 23 | "$1.00", 24 | "1/2", 25 | "1E2", 26 | "1E02", 27 | "1E+02", 28 | "-1", 29 | "-1.00", 30 | "-$1.00", 31 | "-1/2", 32 | "-1E2", 33 | "-1E02", 34 | "-1E+02", 35 | "1/0", 36 | "0/0", 37 | "-2147483648/-1", 38 | "-9223372036854775808/-1", 39 | "-0", 40 | "-0.0", 41 | "+0", 42 | "+0.0", 43 | "0.00", 44 | "0..0", 45 | ".", 46 | "0.0.0", 47 | "0,00", 48 | "0,,0", 49 | ",", 50 | "0,0,0", 51 | "0.0/0", 52 | "1.0/0.0", 53 | "0.0/0.0", 54 | "1,0/0,0", 55 | "0,0/0,0", 56 | "--1", 57 | "-", 58 | "-.", 59 | "-,", 60 | "999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 61 | "NaN", 62 | "Infinity", 63 | "-Infinity", 64 | "INF", 65 | "1#INF", 66 | "-1#IND", 67 | "1#QNAN", 68 | "1#SNAN", 69 | "1#IND", 70 | "0x0", 71 | "0xffffffff", 72 | "0xffffffffffffffff", 73 | "0xabad1dea", 74 | "123456789012345678901234567890123456789", 75 | "1,000.00", 76 | "1 000.00", 77 | "1'000.00", 78 | "1,000,000.00", 79 | "1 000 000.00", 80 | "1'000'000.00", 81 | "1.000,00", 82 | "1 000,00", 83 | "1'000,00", 84 | "1.000.000,00", 85 | "1 000 000,00", 86 | "1'000'000,00", 87 | "01000", 88 | "08", 89 | "09", 90 | "2.2250738585072011e-308", 91 | ",./;'[]\-=", 92 | "<>?:"{}|_+", 93 | "!@#$%^&*()`~", 94 | "", 95 | "€‚ƒ„†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ", 96 | " …             ​

   ", 97 | "­؀؁؂؃؄؅؜۝܏᠎​‌‍‎‏‪‫‬‭‮⁠⁡⁢⁣⁤⁦⁧⁨⁩𑂽𛲠𛲡𛲢𛲣𝅳𝅴𝅵𝅶𝅷𝅸𝅹𝅺󠀁󠀠󠀡󠀢󠀣󠀤󠀥󠀦󠀧󠀨󠀩󠀪󠀫󠀬󠀭󠀮󠀯󠀰󠀱󠀲󠀳󠀴󠀵󠀶󠀷󠀸󠀹󠀺󠀻󠀼󠀽󠀾󠀿󠁀󠁁󠁂󠁃󠁄󠁅󠁆󠁇󠁈󠁉󠁊󠁋󠁌󠁍󠁎󠁏󠁐󠁑󠁒󠁓󠁔󠁕󠁖󠁗󠁘󠁙󠁚󠁛󠁜󠁝󠁞󠁟󠁠󠁡󠁢󠁣󠁤󠁥󠁦󠁧󠁨󠁩󠁪󠁫󠁬󠁭󠁮󠁯󠁰󠁱󠁲󠁳󠁴󠁵󠁶󠁷󠁸󠁹󠁺󠁻󠁼󠁽󠁾󠁿", 98 | "", 99 | "�", 100 | "Ω≈ç√∫˜µ≤≥÷", 101 | "åß∂ƒ©˙∆˚¬…æ", 102 | "œ∑´®†¥¨ˆøπ“‘", 103 | "¡™£¢∞§¶•ªº–≠", 104 | "¸˛Ç◊ı˜Â¯˘¿", 105 | "ÅÍÎÏ˝ÓÔÒÚÆ☃", 106 | "Œ„´‰ˇÁ¨ˆØ∏”’", 107 | "`⁄€‹›fifl‡°·‚—±", 108 | "⅛⅜⅝⅞", 109 | "ЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя", 110 | "٠١٢٣٤٥٦٧٨٩", 111 | "⁰⁴⁵", 112 | "₀₁₂", 113 | "⁰⁴⁵₀₁₂", 114 | "ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็ ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็ ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็", 115 | "'", 116 | """, 117 | "''", 118 | """", 119 | "'"'", 120 | ""''''"'"", 121 | ""'"'"''''"", 122 | "", 123 | "", 124 | "", 125 | "", 126 | "田中さんにあげて下さい", 127 | "パーティーへ行かないか", 128 | "和製漢語", 129 | "部落格", 130 | "사회과학원 어학연구소", 131 | "찦차를 타고 온 펲시맨과 쑛다리 똠방각하", 132 | "社會科學院語學研究所", 133 | "울란바토르", 134 | "𠜎𠜱𠝹𠱓𠱸𠲖𠳏", 135 | "表ポあA鷗ŒéB逍Üߪąñ丂㐀𠀀", 136 | "Ⱥ", 137 | "Ⱦ", 138 | "ヽ༼ຈل͜ຈ༽ノ ヽ༼ຈل͜ຈ༽ノ", 139 | "(。◕ ∀ ◕。)", 140 | "`ィ(´∀`∩", 141 | "__ロ(,_,*)", 142 | "・( ̄∀ ̄)・:*:", 143 | "゚・✿ヾ╲(。◕‿◕。)╱✿・゚", 144 | ",。・:*:・゜’( ☻ ω ☻ )。・:*:・゜’", 145 | "(╯°□°)╯︵ ┻━┻)", 146 | "(ノಥ益ಥ)ノ ┻━┻", 147 | "┬─┬ノ( º _ ºノ)", 148 | "( ͡° ͜ʖ ͡°)", 149 | "😍", 150 | "👩🏽", 151 | "👾 🙇 💁 🙅 🙆 🙋 🙎 🙍", 152 | "🐵 🙈 🙉 🙊", 153 | "❤️ 💔 💌 💕 💞 💓 💗 💖 💘 💝 💟 💜 💛 💚 💙", 154 | "✋🏿 💪🏿 👐🏿 🙌🏿 👏🏿 🙏🏿", 155 | "🚾 🆒 🆓 🆕 🆖 🆗 🆙 🏧", 156 | "0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟", 157 | "🇺🇸🇷🇺🇸 🇦🇫🇦🇲🇸", 158 | "🇺🇸🇷🇺🇸🇦🇫🇦🇲", 159 | "🇺🇸🇷🇺🇸🇦", 160 | "123", 161 | "١٢٣", 162 | "ثم نفس سقطت وبالتحديد،, جزيرتي باستخدام أن دنو. إذ هنا؟ الستار وتنصيب كان. أهّل ايطاليا، بريطانيا-فرنسا قد أخذ. سليمان، إتفاقية بين ما, يذكر الحدود أي بعد, معاملة بولندا، الإطلاق عل إيو.", 163 | "בְּרֵאשִׁית, בָּרָא אֱלֹהִים, אֵת הַשָּׁמַיִם, וְאֵת הָאָרֶץ", 164 | "הָיְתָהtestالصفحات التّحول", 165 | "﷽", 166 | "ﷺ", 167 | "مُنَاقَشَةُ سُبُلِ اِسْتِخْدَامِ اللُّغَةِ فِي النُّظُمِ الْقَائِمَةِ وَفِيم يَخُصَّ التَّطْبِيقَاتُ الْحاسُوبِيَّةُ، ", 168 | "‪‪test‪", 169 | "‫test‫", 170 | "
test
", 171 | "test⁠test‫", 172 | "⁦test⁧", 173 | "Ṱ̺̺̕o͞ ̷i̲̬͇̪͙n̝̗͕v̟̜̘̦͟o̶̙̰̠kè͚̮̺̪̹̱̤ ̖t̝͕̳̣̻̪͞h̼͓̲̦̳̘̲e͇̣̰̦̬͎ ̢̼̻̱̘h͚͎͙̜̣̲ͅi̦̲̣̰̤v̻͍e̺̭̳̪̰-m̢iͅn̖̺̞̲̯̰d̵̼̟͙̩̼̘̳ ̞̥̱̳̭r̛̗̘e͙p͠r̼̞̻̭̗e̺̠̣͟s̘͇̳͍̝͉e͉̥̯̞̲͚̬͜ǹ̬͎͎̟̖͇̤t͍̬̤͓̼̭͘ͅi̪̱n͠g̴͉ ͏͉ͅc̬̟h͡a̫̻̯͘o̫̟̖͍̙̝͉s̗̦̲.̨̹͈̣", 174 | "̡͓̞ͅI̗̘̦͝n͇͇͙v̮̫ok̲̫̙͈i̖͙̭̹̠̞n̡̻̮̣̺g̲͈͙̭͙̬͎ ̰t͔̦h̞̲e̢̤ ͍̬̲͖f̴̘͕̣è͖ẹ̥̩l͖͔͚i͓͚̦͠n͖͍̗͓̳̮g͍ ̨o͚̪͡f̘̣̬ ̖̘͖̟͙̮c҉͔̫͖͓͇͖ͅh̵̤̣͚͔á̗̼͕ͅo̼̣̥s̱͈̺̖̦̻͢.̛̖̞̠̫̰", 175 | "̗̺͖̹̯͓Ṯ̤͍̥͇͈h̲́e͏͓̼̗̙̼̣͔ ͇̜̱̠͓͍ͅN͕͠e̗̱z̘̝̜̺͙p̤̺̹͍̯͚e̠̻̠͜r̨̤͍̺̖͔̖̖d̠̟̭̬̝͟i̦͖̩͓͔̤a̠̗̬͉̙n͚͜ ̻̞̰͚ͅh̵͉i̳̞v̢͇ḙ͎͟-҉̭̩̼͔m̤̭̫i͕͇̝̦n̗͙ḍ̟ ̯̲͕͞ǫ̟̯̰̲͙̻̝f ̪̰̰̗̖̭̘͘c̦͍̲̞͍̩̙ḥ͚a̮͎̟̙͜ơ̩̹͎s̤.̝̝ ҉Z̡̖̜͖̰̣͉̜a͖̰͙̬͡l̲̫̳͍̩g̡̟̼̱͚̞̬ͅo̗͜.̟", 176 | "̦H̬̤̗̤͝e͜ ̜̥̝̻͍̟́w̕h̖̯͓o̝͙̖͎̱̮ ҉̺̙̞̟͈W̷̼̭a̺̪͍į͈͕̭͙̯̜t̶̼̮s̘͙͖̕ ̠̫̠B̻͍͙͉̳ͅe̵h̵̬͇̫͙i̹͓̳̳̮͎̫̕n͟d̴̪̜̖ ̰͉̩͇͙̲͞ͅT͖̼͓̪͢h͏͓̮̻e̬̝̟ͅ ̤̹̝W͙̞̝͔͇͝ͅa͏͓͔̹̼̣l̴͔̰̤̟͔ḽ̫.͕", 177 | "Z̮̞̠͙͔ͅḀ̗̞͈̻̗Ḷ͙͎̯̹̞͓G̻O̭̗̮", 178 | "˙ɐnbᴉlɐ ɐuƃɐɯ ǝɹolop ʇǝ ǝɹoqɐl ʇn ʇunpᴉpᴉɔuᴉ ɹodɯǝʇ poɯsnᴉǝ op pǝs 'ʇᴉlǝ ƃuᴉɔsᴉdᴉpɐ ɹnʇǝʇɔǝsuoɔ 'ʇǝɯɐ ʇᴉs ɹolop ɯnsdᴉ ɯǝɹo˥", 179 | "00˙Ɩ$-", 180 | "The quick brown fox jumps over the lazy dog", 181 | "𝐓𝐡𝐞 𝐪𝐮𝐢𝐜𝐤 𝐛𝐫𝐨𝐰𝐧 𝐟𝐨𝐱 𝐣𝐮𝐦𝐩𝐬 𝐨𝐯𝐞𝐫 𝐭𝐡𝐞 𝐥𝐚𝐳𝐲 𝐝𝐨𝐠", 182 | "𝕿𝖍𝖊 𝖖𝖚𝖎𝖈𝖐 𝖇𝖗𝖔𝖜𝖓 𝖋𝖔𝖝 𝖏𝖚𝖒𝖕𝖘 𝖔𝖛𝖊𝖗 𝖙𝖍𝖊 𝖑𝖆𝖟𝖞 𝖉𝖔𝖌", 183 | "𝑻𝒉𝒆 𝒒𝒖𝒊𝒄𝒌 𝒃𝒓𝒐𝒘𝒏 𝒇𝒐𝒙 𝒋𝒖𝒎𝒑𝒔 𝒐𝒗𝒆𝒓 𝒕𝒉𝒆 𝒍𝒂𝒛𝒚 𝒅𝒐𝒈", 184 | "𝓣𝓱𝓮 𝓺𝓾𝓲𝓬𝓴 𝓫𝓻𝓸𝔀𝓷 𝓯𝓸𝔁 𝓳𝓾𝓶𝓹𝓼 𝓸𝓿𝓮𝓻 𝓽𝓱𝓮 𝓵𝓪𝔃𝔂 𝓭𝓸𝓰", 185 | "𝕋𝕙𝕖 𝕢𝕦𝕚𝕔𝕜 𝕓𝕣𝕠𝕨𝕟 𝕗𝕠𝕩 𝕛𝕦𝕞𝕡𝕤 𝕠𝕧𝕖𝕣 𝕥𝕙𝕖 𝕝𝕒𝕫𝕪 𝕕𝕠𝕘", 186 | "𝚃𝚑𝚎 𝚚𝚞𝚒𝚌𝚔 𝚋𝚛𝚘𝚠𝚗 𝚏𝚘𝚡 𝚓𝚞𝚖𝚙𝚜 𝚘𝚟𝚎𝚛 𝚝𝚑𝚎 𝚕𝚊𝚣𝚢 𝚍𝚘𝚐", 187 | "⒯⒣⒠ ⒬⒰⒤⒞⒦ ⒝⒭⒪⒲⒩ ⒡⒪⒳ ⒥⒰⒨⒫⒮ ⒪⒱⒠⒭ ⒯⒣⒠ ⒧⒜⒵⒴ ⒟⒪⒢", 188 | "", 189 | "<script>alert('123');</script>", 190 | "", 191 | "", 192 | "">", 193 | "'>", 194 | ">", 195 | "", 196 | "< / script >< script >alert(123)< / script >", 197 | " onfocus=JaVaSCript:alert(123) autofocus", 198 | "" onfocus=JaVaSCript:alert(123) autofocus", 199 | "' onfocus=JaVaSCript:alert(123) autofocus", 200 | "<script>alert(123)</script>", 201 | "ript>alert(123)ript>", 202 | "-->", 203 | "";alert(123);t="", 204 | "';alert(123);t='", 205 | "JavaSCript:alert(123)", 206 | ";alert(123);", 207 | "src=JaVaSCript:prompt(132)", 208 | ""><\x3Cscript>javascript:alert(1)", 221 | "'`"><\x00script>javascript:alert(1)", 222 | "ABC
DEF", 223 | "ABC
DEF", 224 | "ABC
DEF", 225 | "ABC
DEF", 226 | "ABC
DEF", 227 | "ABC
DEF", 228 | "ABC
DEF", 229 | "ABC
DEF", 230 | "ABC
DEF", 231 | "ABC
DEF", 232 | "ABC
DEF", 233 | "ABC
DEF", 234 | "ABC
DEF", 235 | "ABC
DEF", 236 | "ABC
DEF", 237 | "ABC
DEF", 238 | "ABC
DEF", 239 | "ABC
DEF", 240 | "ABC
DEF", 241 | "ABC
DEF", 242 | "ABC
DEF", 243 | "ABC
DEF", 244 | "ABC
DEF", 245 | "ABC
DEF", 246 | "ABC
DEF", 247 | "ABC
DEF", 248 | "ABC
DEF", 249 | "test", 250 | "test", 251 | "test", 252 | "test", 253 | "test", 254 | "test", 255 | "test", 256 | "test", 257 | "test", 258 | "test", 259 | "test", 260 | "test", 261 | "test", 262 | "test", 263 | "test", 264 | "test", 265 | "test", 266 | "test", 267 | "test", 268 | "test", 269 | "test", 270 | "test", 271 | "test", 272 | "test", 273 | "test", 274 | "test", 275 | "test", 276 | "test", 277 | "test", 278 | "test", 279 | "test", 280 | "test", 281 | "test", 282 | "test", 283 | "test", 284 | "test", 285 | "test", 286 | "test", 287 | "test", 288 | "test", 289 | "test", 290 | "test", 291 | "test", 292 | "test", 293 | "test", 294 | "test", 295 | "test", 296 | "test", 297 | "test", 298 | "test", 299 | "test", 300 | "test", 301 | "test", 302 | "test", 303 | "test", 304 | "test", 305 | "test", 306 | "`"'>", 307 | "`"'>", 308 | "`"'>", 309 | "`"'>", 310 | "`"'>", 311 | "`"'>", 312 | "`"'>", 313 | "`"'>", 314 | "`"'>", 315 | "`"'>", 316 | ""`'>", 317 | ""`'>", 318 | ""`'>", 319 | ""`'>", 320 | ""`'>", 321 | ""`'>", 322 | ""`'>", 323 | ""`'>", 324 | ""`'>", 325 | ""`'>", 326 | ""`'>", 327 | ""`'>", 328 | ""`'>", 329 | ""`'>", 330 | ""`'>", 331 | ""`'>", 332 | ""`'>", 333 | ""`'>", 334 | ""`'>", 335 | ""`'>", 336 | ""`'>", 337 | ""`'>", 338 | ""`'>", 339 | ""`'>", 340 | ""`'>", 341 | ""`'>", 342 | ""`'>", 343 | ""`'>", 344 | ""`'>", 345 | ""`'>", 346 | ""`'>", 347 | ""`'>", 348 | ""`'>", 349 | ""`'>", 350 | ""`'>", 351 | ""`'>", 352 | ""`'>", 353 | "", 354 | "", 355 | "", 356 | "", 357 | "", 358 | "", 359 | "", 360 | "", 361 | "", 362 | "", 363 | "", 364 | "", 365 | "", 366 | "", 367 | "", 368 | "", 369 | "", 370 | "", 371 | "", 372 | "", 373 | "", 374 | "", 375 | "", 376 | "", 377 | "", 378 | "", 379 | "", 380 | "", 381 | "", 382 | "", 383 | "", 384 | "", 385 | "", 386 | "", 387 | "XXX", 388 | "", 389 | "", 390 | "", 391 | "<a href=http://foo.bar/#x=`y></a><img alt="`><img src=x:x onerror=javascript:alert(1)></a>">", 392 | "<!--[if]><script>javascript:alert(1)</script -->", 393 | "<!--[if<img src=x onerror=javascript:alert(1)//]> -->", 394 | "<script src="/\%(jscript)s"></script>", 395 | "<script src="\\%(jscript)s"></script>", 396 | "<IMG """><SCRIPT>alert("XSS")</SCRIPT>">", 397 | "<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>", 398 | "<IMG SRC=# onmouseover="alert('xxs')">", 399 | "<IMG SRC= onmouseover="alert('xxs')">", 400 | "<IMG onmouseover="alert('xxs')">", 401 | "<IMG SRC=javascript:alert('XSS')>", 402 | "<IMG SRC=javascript:alert('XSS')>", 403 | "<IMG SRC=javascript:alert('XSS')>", 404 | "<IMG SRC="jav ascript:alert('XSS');">", 405 | "<IMG SRC="jav ascript:alert('XSS');">", 406 | "<IMG SRC="jav ascript:alert('XSS');">", 407 | "<IMG SRC="jav ascript:alert('XSS');">", 408 | "perl -e 'print "<IMG SRC=java\0script:alert(\"XSS\")>";' > out", 409 | "<IMG SRC="  javascript:alert('XSS');">", 410 | "<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>", 411 | "<BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")>", 412 | "<SCRIPT/SRC="http://ha.ckers.org/xss.js"></SCRIPT>", 413 | "<<SCRIPT>alert("XSS");//<</SCRIPT>", 414 | "<SCRIPT SRC=http://ha.ckers.org/xss.js?< B >", 415 | "<SCRIPT SRC=//ha.ckers.org/.j>", 416 | "<IMG SRC="javascript:alert('XSS')"", 417 | "<iframe src=http://ha.ckers.org/scriptlet.html <", 418 | "\";alert('XSS');//", 419 | "<u oncopy=alert()> Copy me</u>", 420 | "<i onwheel=alert(1)> Scroll over me </i>", 421 | "<plaintext>", 422 | "http://a/%%30%30", 423 | "</textarea><script>alert(123)</script>", 424 | "1;DROP TABLE users", 425 | "1'; DROP TABLE users-- 1", 426 | "' OR 1=1 -- 1", 427 | "' OR '1'='1", 428 | " ", 429 | "%", 430 | "_", 431 | "-", 432 | "--", 433 | "--version", 434 | "--help", 435 | "$USER", 436 | "/dev/null; touch /tmp/blns.fail ; echo", 437 | "`touch /tmp/blns.fail`", 438 | "$(touch /tmp/blns.fail)", 439 | "@{[system "touch /tmp/blns.fail"]}", 440 | "eval("puts 'hello world'")", 441 | "System("ls -al /")", 442 | "`ls -al /`", 443 | "Kernel.exec("ls -al /")", 444 | "Kernel.exit(1)", 445 | "%x('ls -al /')", 446 | "<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE foo [ <!ELEMENT foo ANY ><!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo>", 447 | "$HOME", 448 | "$ENV{'HOME'}", 449 | "%d", 450 | "%s%s%s%s%s", 451 | "{0}", 452 | "%*.*s", 453 | "%@", 454 | "%n", 455 | "File:///", 456 | "../../../../../../../../../../../etc/passwd%00", 457 | "../../../../../../../../../../../etc/hosts", 458 | "() { 0; }; touch /tmp/blns.shellshock1.fail;", 459 | "() { _; } >_[$($())] { touch /tmp/blns.shellshock2.fail; }", 460 | "<<< %s(un='%s') = %u", 461 | "+++ATH0", 462 | "CON", 463 | "PRN", 464 | "AUX", 465 | "CLOCK$", 466 | "NUL", 467 | "A:", 468 | "ZZ:", 469 | "COM1", 470 | "LPT1", 471 | "LPT2", 472 | "LPT3", 473 | "COM2", 474 | "COM3", 475 | "COM4", 476 | "DCC SEND STARTKEYLOGGER 0 0 0", 477 | "Scunthorpe General Hospital", 478 | "Penistone Community Church", 479 | "Lightwater Country Park", 480 | "Jimmy Clitheroe", 481 | "Horniman Museum", 482 | "shitake mushrooms", 483 | "RomansInSussex.co.uk", 484 | "http://www.cum.qc.ca/", 485 | "Craig Cockburn, Software Specialist", 486 | "Linda Callahan", 487 | "Dr. Herman I. Libshitz", 488 | "magna cum laude", 489 | "Super Bowl XXX", 490 | "medieval erection of parapets", 491 | "evaluate", 492 | "mocha", 493 | "expression", 494 | "Arsenal canal", 495 | "classic", 496 | "Tyson Gay", 497 | "Dick Van Dyke", 498 | "basement", 499 | "If you're reading this, you've been in a coma for almost 20 years now. We're trying a new technique. We don't know where this message will end up in your dream, but we hope it works. Please wake up, we miss you.", 500 | "Roses are red, violets are blue. Hope you enjoy terminal hue", 501 | "But now...for my greatest trick...", 502 | "The quick brown fox... [Beeeep]", 503 | "Powerلُلُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ冗", 504 | "🏳0🌈️", 505 | "జ్ఞ‌ా" 506 | ] 507 | -------------------------------------------------------------------------------- /src/test/resources/naughty_strings.json: -------------------------------------------------------------------------------- 1 | [ 2 | "", 3 | "undefined", 4 | "undef", 5 | "null", 6 | "NULL", 7 | "(null)", 8 | "nil", 9 | "NIL", 10 | "true", 11 | "false", 12 | "True", 13 | "False", 14 | "TRUE", 15 | "FALSE", 16 | "None", 17 | "hasOwnProperty", 18 | "\\", 19 | "\\\\", 20 | "0", 21 | "1", 22 | "1.00", 23 | "$1.00", 24 | "1/2", 25 | "1E2", 26 | "1E02", 27 | "1E+02", 28 | "-1", 29 | "-1.00", 30 | "-$1.00", 31 | "-1/2", 32 | "-1E2", 33 | "-1E02", 34 | "-1E+02", 35 | "1/0", 36 | "0/0", 37 | "-2147483648/-1", 38 | "-9223372036854775808/-1", 39 | "-0", 40 | "-0.0", 41 | "+0", 42 | "+0.0", 43 | "0.00", 44 | "0..0", 45 | ".", 46 | "0.0.0", 47 | "0,00", 48 | "0,,0", 49 | ",", 50 | "0,0,0", 51 | "0.0/0", 52 | "1.0/0.0", 53 | "0.0/0.0", 54 | "1,0/0,0", 55 | "0,0/0,0", 56 | "--1", 57 | "-", 58 | "-.", 59 | "-,", 60 | "999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 61 | "NaN", 62 | "Infinity", 63 | "-Infinity", 64 | "INF", 65 | "1#INF", 66 | "-1#IND", 67 | "1#QNAN", 68 | "1#SNAN", 69 | "1#IND", 70 | "0x0", 71 | "0xffffffff", 72 | "0xffffffffffffffff", 73 | "0xabad1dea", 74 | "123456789012345678901234567890123456789", 75 | "1,000.00", 76 | "1 000.00", 77 | "1'000.00", 78 | "1,000,000.00", 79 | "1 000 000.00", 80 | "1'000'000.00", 81 | "1.000,00", 82 | "1 000,00", 83 | "1'000,00", 84 | "1.000.000,00", 85 | "1 000 000,00", 86 | "1'000'000,00", 87 | "01000", 88 | "08", 89 | "09", 90 | "2.2250738585072011e-308", 91 | ",./;'[]\\-=", 92 | "<>?:\"{}|_+", 93 | "!@#$%^&*()`~", 94 | "\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f", 95 | "€‚ƒ„†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ", 96 | "\t\u000b\f …             ​

   ", 97 | "­؀؁؂؃؄؅؜۝܏᠎​‌‍‎‏‪‫‬‭‮⁠⁡⁢⁣⁤⁦⁧⁨⁩𑂽𛲠𛲡𛲢𛲣𝅳𝅴𝅵𝅶𝅷𝅸𝅹𝅺󠀁󠀠󠀡󠀢󠀣󠀤󠀥󠀦󠀧󠀨󠀩󠀪󠀫󠀬󠀭󠀮󠀯󠀰󠀱󠀲󠀳󠀴󠀵󠀶󠀷󠀸󠀹󠀺󠀻󠀼󠀽󠀾󠀿󠁀󠁁󠁂󠁃󠁄󠁅󠁆󠁇󠁈󠁉󠁊󠁋󠁌󠁍󠁎󠁏󠁐󠁑󠁒󠁓󠁔󠁕󠁖󠁗󠁘󠁙󠁚󠁛󠁜󠁝󠁞󠁟󠁠󠁡󠁢󠁣󠁤󠁥󠁦󠁧󠁨󠁩󠁪󠁫󠁬󠁭󠁮󠁯󠁰󠁱󠁲󠁳󠁴󠁵󠁶󠁷󠁸󠁹󠁺󠁻󠁼󠁽󠁾󠁿", 98 | "", 99 | "�", 100 | "Ω≈ç√∫˜µ≤≥÷", 101 | "åß∂ƒ©˙∆˚¬…æ", 102 | "œ∑´®†¥¨ˆøπ“‘", 103 | "¡™£¢∞§¶•ªº–≠", 104 | "¸˛Ç◊ı˜Â¯˘¿", 105 | "ÅÍÎÏ˝ÓÔÒÚÆ☃", 106 | "Œ„´‰ˇÁ¨ˆØ∏”’", 107 | "`⁄€‹›fifl‡°·‚—±", 108 | "⅛⅜⅝⅞", 109 | "ЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя", 110 | "٠١٢٣٤٥٦٧٨٩", 111 | "⁰⁴⁵", 112 | "₀₁₂", 113 | "⁰⁴⁵₀₁₂", 114 | "ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็ ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็ ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็", 115 | "'", 116 | "\"", 117 | "''", 118 | "\"\"", 119 | "'\"'", 120 | "\"''''\"'\"", 121 | "\"'\"'\"''''\"", 122 | "<foo val=“bar” />", 123 | "<foo val=“bar” />", 124 | "<foo val=”bar“ />", 125 | "<foo val=`bar' />", 126 | "田中さんにあげて下さい", 127 | "パーティーへ行かないか", 128 | "和製漢語", 129 | "部落格", 130 | "사회과학원 어학연구소", 131 | "찦차를 타고 온 펲시맨과 쑛다리 똠방각하", 132 | "社會科學院語學研究所", 133 | "울란바토르", 134 | "𠜎𠜱𠝹𠱓𠱸𠲖𠳏", 135 | "表ポあA鷗ŒéB逍Üߪąñ丂㐀𠀀", 136 | "Ⱥ", 137 | "Ⱦ", 138 | "ヽ༼ຈل͜ຈ༽ノ ヽ༼ຈل͜ຈ༽ノ", 139 | "(。◕ ∀ ◕。)", 140 | "`ィ(´∀`∩", 141 | "__ロ(,_,*)", 142 | "・( ̄∀ ̄)・:*:", 143 | "゚・✿ヾ╲(。◕‿◕。)╱✿・゚", 144 | ",。・:*:・゜’( ☻ ω ☻ )。・:*:・゜’", 145 | "(╯°□°)╯︵ ┻━┻)", 146 | "(ノಥ益ಥ)ノ ┻━┻", 147 | "┬─┬ノ( º _ ºノ)", 148 | "( ͡° ͜ʖ ͡°)", 149 | "😍", 150 | "👩🏽", 151 | "👾 🙇 💁 🙅 🙆 🙋 🙎 🙍", 152 | "🐵 🙈 🙉 🙊", 153 | "❤️ 💔 💌 💕 💞 💓 💗 💖 💘 💝 💟 💜 💛 💚 💙", 154 | "✋🏿 💪🏿 👐🏿 🙌🏿 👏🏿 🙏🏿", 155 | "🚾 🆒 🆓 🆕 🆖 🆗 🆙 🏧", 156 | "0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟", 157 | "🇺🇸🇷🇺🇸 🇦🇫🇦🇲🇸", 158 | "🇺🇸🇷🇺🇸🇦🇫🇦🇲", 159 | "🇺🇸🇷🇺🇸🇦", 160 | "123", 161 | "١٢٣", 162 | "ثم نفس سقطت وبالتحديد،, جزيرتي باستخدام أن دنو. إذ هنا؟ الستار وتنصيب كان. أهّل ايطاليا، بريطانيا-فرنسا قد أخذ. سليمان، إتفاقية بين ما, يذكر الحدود أي بعد, معاملة بولندا، الإطلاق عل إيو.", 163 | "בְּרֵאשִׁית, בָּרָא אֱלֹהִים, אֵת הַשָּׁמַיִם, וְאֵת הָאָרֶץ", 164 | "הָיְתָהtestالصفحات التّحول", 165 | "﷽", 166 | "ﷺ", 167 | "مُنَاقَشَةُ سُبُلِ اِسْتِخْدَامِ اللُّغَةِ فِي النُّظُمِ الْقَائِمَةِ وَفِيم يَخُصَّ التَّطْبِيقَاتُ الْحاسُوبِيَّةُ، ", 168 | "‪‪test‪", 169 | "‫test‫", 170 | "
test
", 171 | "test⁠test‫", 172 | "⁦test⁧", 173 | "Ṱ̺̺̕o͞ ̷i̲̬͇̪͙n̝̗͕v̟̜̘̦͟o̶̙̰̠kè͚̮̺̪̹̱̤ ̖t̝͕̳̣̻̪͞h̼͓̲̦̳̘̲e͇̣̰̦̬͎ ̢̼̻̱̘h͚͎͙̜̣̲ͅi̦̲̣̰̤v̻͍e̺̭̳̪̰-m̢iͅn̖̺̞̲̯̰d̵̼̟͙̩̼̘̳ ̞̥̱̳̭r̛̗̘e͙p͠r̼̞̻̭̗e̺̠̣͟s̘͇̳͍̝͉e͉̥̯̞̲͚̬͜ǹ̬͎͎̟̖͇̤t͍̬̤͓̼̭͘ͅi̪̱n͠g̴͉ ͏͉ͅc̬̟h͡a̫̻̯͘o̫̟̖͍̙̝͉s̗̦̲.̨̹͈̣", 174 | "̡͓̞ͅI̗̘̦͝n͇͇͙v̮̫ok̲̫̙͈i̖͙̭̹̠̞n̡̻̮̣̺g̲͈͙̭͙̬͎ ̰t͔̦h̞̲e̢̤ ͍̬̲͖f̴̘͕̣è͖ẹ̥̩l͖͔͚i͓͚̦͠n͖͍̗͓̳̮g͍ ̨o͚̪͡f̘̣̬ ̖̘͖̟͙̮c҉͔̫͖͓͇͖ͅh̵̤̣͚͔á̗̼͕ͅo̼̣̥s̱͈̺̖̦̻͢.̛̖̞̠̫̰", 175 | "̗̺͖̹̯͓Ṯ̤͍̥͇͈h̲́e͏͓̼̗̙̼̣͔ ͇̜̱̠͓͍ͅN͕͠e̗̱z̘̝̜̺͙p̤̺̹͍̯͚e̠̻̠͜r̨̤͍̺̖͔̖̖d̠̟̭̬̝͟i̦͖̩͓͔̤a̠̗̬͉̙n͚͜ ̻̞̰͚ͅh̵͉i̳̞v̢͇ḙ͎͟-҉̭̩̼͔m̤̭̫i͕͇̝̦n̗͙ḍ̟ ̯̲͕͞ǫ̟̯̰̲͙̻̝f ̪̰̰̗̖̭̘͘c̦͍̲̞͍̩̙ḥ͚a̮͎̟̙͜ơ̩̹͎s̤.̝̝ ҉Z̡̖̜͖̰̣͉̜a͖̰͙̬͡l̲̫̳͍̩g̡̟̼̱͚̞̬ͅo̗͜.̟", 176 | "̦H̬̤̗̤͝e͜ ̜̥̝̻͍̟́w̕h̖̯͓o̝͙̖͎̱̮ ҉̺̙̞̟͈W̷̼̭a̺̪͍į͈͕̭͙̯̜t̶̼̮s̘͙͖̕ ̠̫̠B̻͍͙͉̳ͅe̵h̵̬͇̫͙i̹͓̳̳̮͎̫̕n͟d̴̪̜̖ ̰͉̩͇͙̲͞ͅT͖̼͓̪͢h͏͓̮̻e̬̝̟ͅ ̤̹̝W͙̞̝͔͇͝ͅa͏͓͔̹̼̣l̴͔̰̤̟͔ḽ̫.͕", 177 | "Z̮̞̠͙͔ͅḀ̗̞͈̻̗Ḷ͙͎̯̹̞͓G̻O̭̗̮", 178 | "˙ɐnbᴉlɐ ɐuƃɐɯ ǝɹolop ʇǝ ǝɹoqɐl ʇn ʇunpᴉpᴉɔuᴉ ɹodɯǝʇ poɯsnᴉǝ op pǝs 'ʇᴉlǝ ƃuᴉɔsᴉdᴉpɐ ɹnʇǝʇɔǝsuoɔ 'ʇǝɯɐ ʇᴉs ɹolop ɯnsdᴉ ɯǝɹo˥", 179 | "00˙Ɩ$-", 180 | "The quick brown fox jumps over the lazy dog", 181 | "𝐓𝐡𝐞 𝐪𝐮𝐢𝐜𝐤 𝐛𝐫𝐨𝐰𝐧 𝐟𝐨𝐱 𝐣𝐮𝐦𝐩𝐬 𝐨𝐯𝐞𝐫 𝐭𝐡𝐞 𝐥𝐚𝐳𝐲 𝐝𝐨𝐠", 182 | "𝕿𝖍𝖊 𝖖𝖚𝖎𝖈𝖐 𝖇𝖗𝖔𝖜𝖓 𝖋𝖔𝖝 𝖏𝖚𝖒𝖕𝖘 𝖔𝖛𝖊𝖗 𝖙𝖍𝖊 𝖑𝖆𝖟𝖞 𝖉𝖔𝖌", 183 | "𝑻𝒉𝒆 𝒒𝒖𝒊𝒄𝒌 𝒃𝒓𝒐𝒘𝒏 𝒇𝒐𝒙 𝒋𝒖𝒎𝒑𝒔 𝒐𝒗𝒆𝒓 𝒕𝒉𝒆 𝒍𝒂𝒛𝒚 𝒅𝒐𝒈", 184 | "𝓣𝓱𝓮 𝓺𝓾𝓲𝓬𝓴 𝓫𝓻𝓸𝔀𝓷 𝓯𝓸𝔁 𝓳𝓾𝓶𝓹𝓼 𝓸𝓿𝓮𝓻 𝓽𝓱𝓮 𝓵𝓪𝔃𝔂 𝓭𝓸𝓰", 185 | "𝕋𝕙𝕖 𝕢𝕦𝕚𝕔𝕜 𝕓𝕣𝕠𝕨𝕟 𝕗𝕠𝕩 𝕛𝕦𝕞𝕡𝕤 𝕠𝕧𝕖𝕣 𝕥𝕙𝕖 𝕝𝕒𝕫𝕪 𝕕𝕠𝕘", 186 | "𝚃𝚑𝚎 𝚚𝚞𝚒𝚌𝚔 𝚋𝚛𝚘𝚠𝚗 𝚏𝚘𝚡 𝚓𝚞𝚖𝚙𝚜 𝚘𝚟𝚎𝚛 𝚝𝚑𝚎 𝚕𝚊𝚣𝚢 𝚍𝚘𝚐", 187 | "⒯⒣⒠ ⒬⒰⒤⒞⒦ ⒝⒭⒪⒲⒩ ⒡⒪⒳ ⒥⒰⒨⒫⒮ ⒪⒱⒠⒭ ⒯⒣⒠ ⒧⒜⒵⒴ ⒟⒪⒢", 188 | "<script>alert(123)</script>", 189 | "<script>alert('123');</script>", 190 | "<img src=x onerror=alert(123) />", 191 | "<svg><script>123<1>alert(123)</script>", 192 | "\"><script>alert(123)</script>", 193 | "'><script>alert(123)</script>", 194 | "><script>alert(123)</script>", 195 | "</script><script>alert(123)</script>", 196 | "< / script >< script >alert(123)< / script >", 197 | " onfocus=JaVaSCript:alert(123) autofocus", 198 | "\" onfocus=JaVaSCript:alert(123) autofocus", 199 | "' onfocus=JaVaSCript:alert(123) autofocus", 200 | "<script>alert(123)</script>", 201 | "<sc<script>ript>alert(123)</sc</script>ript>", 202 | "--><script>alert(123)</script>", 203 | "\";alert(123);t=\"", 204 | "';alert(123);t='", 205 | "JavaSCript:alert(123)", 206 | ";alert(123);", 207 | "src=JaVaSCript:prompt(132)", 208 | "\"><script>alert(123);</script x=\"", 209 | "'><script>alert(123);</script x='", 210 | "><script>alert(123);</script x=", 211 | "\" autofocus onkeyup=\"javascript:alert(123)", 212 | "' autofocus onkeyup='javascript:alert(123)", 213 | "<script\\x20type=\"text/javascript\">javascript:alert(1);</script>", 214 | "<script\\x3Etype=\"text/javascript\">javascript:alert(1);</script>", 215 | "<script\\x0Dtype=\"text/javascript\">javascript:alert(1);</script>", 216 | "<script\\x09type=\"text/javascript\">javascript:alert(1);</script>", 217 | "<script\\x0Ctype=\"text/javascript\">javascript:alert(1);</script>", 218 | "<script\\x2Ftype=\"text/javascript\">javascript:alert(1);</script>", 219 | "<script\\x0Atype=\"text/javascript\">javascript:alert(1);</script>", 220 | "'`\"><\\x3Cscript>javascript:alert(1)</script>", 221 | "'`\"><\\x00script>javascript:alert(1)</script>", 222 | "ABC<div style=\"x\\x3Aexpression(javascript:alert(1)\">DEF", 223 | "ABC<div style=\"x:expression\\x5C(javascript:alert(1)\">DEF", 224 | "ABC<div style=\"x:expression\\x00(javascript:alert(1)\">DEF", 225 | "ABC<div style=\"x:exp\\x00ression(javascript:alert(1)\">DEF", 226 | "ABC<div style=\"x:exp\\x5Cression(javascript:alert(1)\">DEF", 227 | "ABC<div style=\"x:\\x0Aexpression(javascript:alert(1)\">DEF", 228 | "ABC<div style=\"x:\\x09expression(javascript:alert(1)\">DEF", 229 | "ABC<div style=\"x:\\xE3\\x80\\x80expression(javascript:alert(1)\">DEF", 230 | "ABC<div style=\"x:\\xE2\\x80\\x84expression(javascript:alert(1)\">DEF", 231 | "ABC<div style=\"x:\\xC2\\xA0expression(javascript:alert(1)\">DEF", 232 | "ABC<div style=\"x:\\xE2\\x80\\x80expression(javascript:alert(1)\">DEF", 233 | "ABC<div style=\"x:\\xE2\\x80\\x8Aexpression(javascript:alert(1)\">DEF", 234 | "ABC<div style=\"x:\\x0Dexpression(javascript:alert(1)\">DEF", 235 | "ABC<div style=\"x:\\x0Cexpression(javascript:alert(1)\">DEF", 236 | "ABC<div style=\"x:\\xE2\\x80\\x87expression(javascript:alert(1)\">DEF", 237 | "ABC<div style=\"x:\\xEF\\xBB\\xBFexpression(javascript:alert(1)\">DEF", 238 | "ABC<div style=\"x:\\x20expression(javascript:alert(1)\">DEF", 239 | "ABC<div style=\"x:\\xE2\\x80\\x88expression(javascript:alert(1)\">DEF", 240 | "ABC<div style=\"x:\\x00expression(javascript:alert(1)\">DEF", 241 | "ABC<div style=\"x:\\xE2\\x80\\x8Bexpression(javascript:alert(1)\">DEF", 242 | "ABC<div style=\"x:\\xE2\\x80\\x86expression(javascript:alert(1)\">DEF", 243 | "ABC<div style=\"x:\\xE2\\x80\\x85expression(javascript:alert(1)\">DEF", 244 | "ABC<div style=\"x:\\xE2\\x80\\x82expression(javascript:alert(1)\">DEF", 245 | "ABC<div style=\"x:\\x0Bexpression(javascript:alert(1)\">DEF", 246 | "ABC<div style=\"x:\\xE2\\x80\\x81expression(javascript:alert(1)\">DEF", 247 | "ABC<div style=\"x:\\xE2\\x80\\x83expression(javascript:alert(1)\">DEF", 248 | "ABC<div style=\"x:\\xE2\\x80\\x89expression(javascript:alert(1)\">DEF", 249 | "<a href=\"\\x0Bjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 250 | "<a href=\"\\x0Fjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 251 | "<a href=\"\\xC2\\xA0javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 252 | "<a href=\"\\x05javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 253 | "<a href=\"\\xE1\\xA0\\x8Ejavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 254 | "<a href=\"\\x18javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 255 | "<a href=\"\\x11javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 256 | "<a href=\"\\xE2\\x80\\x88javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 257 | "<a href=\"\\xE2\\x80\\x89javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 258 | "<a href=\"\\xE2\\x80\\x80javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 259 | "<a href=\"\\x17javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 260 | "<a href=\"\\x03javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 261 | "<a href=\"\\x0Ejavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 262 | "<a href=\"\\x1Ajavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 263 | "<a href=\"\\x00javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 264 | "<a href=\"\\x10javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 265 | "<a href=\"\\xE2\\x80\\x82javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 266 | "<a href=\"\\x20javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 267 | "<a href=\"\\x13javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 268 | "<a href=\"\\x09javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 269 | "<a href=\"\\xE2\\x80\\x8Ajavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 270 | "<a href=\"\\x14javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 271 | "<a href=\"\\x19javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 272 | "<a href=\"\\xE2\\x80\\xAFjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 273 | "<a href=\"\\x1Fjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 274 | "<a href=\"\\xE2\\x80\\x81javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 275 | "<a href=\"\\x1Djavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 276 | "<a href=\"\\xE2\\x80\\x87javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 277 | "<a href=\"\\x07javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 278 | "<a href=\"\\xE1\\x9A\\x80javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 279 | "<a href=\"\\xE2\\x80\\x83javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 280 | "<a href=\"\\x04javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 281 | "<a href=\"\\x01javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 282 | "<a href=\"\\x08javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 283 | "<a href=\"\\xE2\\x80\\x84javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 284 | "<a href=\"\\xE2\\x80\\x86javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 285 | "<a href=\"\\xE3\\x80\\x80javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 286 | "<a href=\"\\x12javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 287 | "<a href=\"\\x0Djavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 288 | "<a href=\"\\x0Ajavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 289 | "<a href=\"\\x0Cjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 290 | "<a href=\"\\x15javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 291 | "<a href=\"\\xE2\\x80\\xA8javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 292 | "<a href=\"\\x16javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 293 | "<a href=\"\\x02javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 294 | "<a href=\"\\x1Bjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 295 | "<a href=\"\\x06javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 296 | "<a href=\"\\xE2\\x80\\xA9javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 297 | "<a href=\"\\xE2\\x80\\x85javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 298 | "<a href=\"\\x1Ejavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 299 | "<a href=\"\\xE2\\x81\\x9Fjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 300 | "<a href=\"\\x1Cjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 301 | "<a href=\"javascript\\x00:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 302 | "<a href=\"javascript\\x3A:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 303 | "<a href=\"javascript\\x09:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 304 | "<a href=\"javascript\\x0D:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 305 | "<a href=\"javascript\\x0A:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", 306 | "`\"'><img src=xxx:x \\x0Aonerror=javascript:alert(1)>", 307 | "`\"'><img src=xxx:x \\x22onerror=javascript:alert(1)>", 308 | "`\"'><img src=xxx:x \\x0Bonerror=javascript:alert(1)>", 309 | "`\"'><img src=xxx:x \\x0Donerror=javascript:alert(1)>", 310 | "`\"'><img src=xxx:x \\x2Fonerror=javascript:alert(1)>", 311 | "`\"'><img src=xxx:x \\x09onerror=javascript:alert(1)>", 312 | "`\"'><img src=xxx:x \\x0Conerror=javascript:alert(1)>", 313 | "`\"'><img src=xxx:x \\x00onerror=javascript:alert(1)>", 314 | "`\"'><img src=xxx:x \\x27onerror=javascript:alert(1)>", 315 | "`\"'><img src=xxx:x \\x20onerror=javascript:alert(1)>", 316 | "\"`'><script>\\x3Bjavascript:alert(1)</script>", 317 | "\"`'><script>\\x0Djavascript:alert(1)</script>", 318 | "\"`'><script>\\xEF\\xBB\\xBFjavascript:alert(1)</script>", 319 | "\"`'><script>\\xE2\\x80\\x81javascript:alert(1)</script>", 320 | "\"`'><script>\\xE2\\x80\\x84javascript:alert(1)</script>", 321 | "\"`'><script>\\xE3\\x80\\x80javascript:alert(1)</script>", 322 | "\"`'><script>\\x09javascript:alert(1)</script>", 323 | "\"`'><script>\\xE2\\x80\\x89javascript:alert(1)</script>", 324 | "\"`'><script>\\xE2\\x80\\x85javascript:alert(1)</script>", 325 | "\"`'><script>\\xE2\\x80\\x88javascript:alert(1)</script>", 326 | "\"`'><script>\\x00javascript:alert(1)</script>", 327 | "\"`'><script>\\xE2\\x80\\xA8javascript:alert(1)</script>", 328 | "\"`'><script>\\xE2\\x80\\x8Ajavascript:alert(1)</script>", 329 | "\"`'><script>\\xE1\\x9A\\x80javascript:alert(1)</script>", 330 | "\"`'><script>\\x0Cjavascript:alert(1)</script>", 331 | "\"`'><script>\\x2Bjavascript:alert(1)</script>", 332 | "\"`'><script>\\xF0\\x90\\x96\\x9Ajavascript:alert(1)</script>", 333 | "\"`'><script>-javascript:alert(1)</script>", 334 | "\"`'><script>\\x0Ajavascript:alert(1)</script>", 335 | "\"`'><script>\\xE2\\x80\\xAFjavascript:alert(1)</script>", 336 | "\"`'><script>\\x7Ejavascript:alert(1)</script>", 337 | "\"`'><script>\\xE2\\x80\\x87javascript:alert(1)</script>", 338 | "\"`'><script>\\xE2\\x81\\x9Fjavascript:alert(1)</script>", 339 | "\"`'><script>\\xE2\\x80\\xA9javascript:alert(1)</script>", 340 | "\"`'><script>\\xC2\\x85javascript:alert(1)</script>", 341 | "\"`'><script>\\xEF\\xBF\\xAEjavascript:alert(1)</script>", 342 | "\"`'><script>\\xE2\\x80\\x83javascript:alert(1)</script>", 343 | "\"`'><script>\\xE2\\x80\\x8Bjavascript:alert(1)</script>", 344 | "\"`'><script>\\xEF\\xBF\\xBEjavascript:alert(1)</script>", 345 | "\"`'><script>\\xE2\\x80\\x80javascript:alert(1)</script>", 346 | "\"`'><script>\\x21javascript:alert(1)</script>", 347 | "\"`'><script>\\xE2\\x80\\x82javascript:alert(1)</script>", 348 | "\"`'><script>\\xE2\\x80\\x86javascript:alert(1)</script>", 349 | "\"`'><script>\\xE1\\xA0\\x8Ejavascript:alert(1)</script>", 350 | "\"`'><script>\\x0Bjavascript:alert(1)</script>", 351 | "\"`'><script>\\x20javascript:alert(1)</script>", 352 | "\"`'><script>\\xC2\\xA0javascript:alert(1)</script>", 353 | "<img \\x00src=x onerror=\"alert(1)\">", 354 | "<img \\x47src=x onerror=\"javascript:alert(1)\">", 355 | "<img \\x11src=x onerror=\"javascript:alert(1)\">", 356 | "<img \\x12src=x onerror=\"javascript:alert(1)\">", 357 | "<img\\x47src=x onerror=\"javascript:alert(1)\">", 358 | "<img\\x10src=x onerror=\"javascript:alert(1)\">", 359 | "<img\\x13src=x onerror=\"javascript:alert(1)\">", 360 | "<img\\x32src=x onerror=\"javascript:alert(1)\">", 361 | "<img\\x47src=x onerror=\"javascript:alert(1)\">", 362 | "<img\\x11src=x onerror=\"javascript:alert(1)\">", 363 | "<img \\x47src=x onerror=\"javascript:alert(1)\">", 364 | "<img \\x34src=x onerror=\"javascript:alert(1)\">", 365 | "<img \\x39src=x onerror=\"javascript:alert(1)\">", 366 | "<img \\x00src=x onerror=\"javascript:alert(1)\">", 367 | "<img src\\x09=x onerror=\"javascript:alert(1)\">", 368 | "<img src\\x10=x onerror=\"javascript:alert(1)\">", 369 | "<img src\\x13=x onerror=\"javascript:alert(1)\">", 370 | "<img src\\x32=x onerror=\"javascript:alert(1)\">", 371 | "<img src\\x12=x onerror=\"javascript:alert(1)\">", 372 | "<img src\\x11=x onerror=\"javascript:alert(1)\">", 373 | "<img src\\x00=x onerror=\"javascript:alert(1)\">", 374 | "<img src\\x47=x onerror=\"javascript:alert(1)\">", 375 | "<img src=x\\x09onerror=\"javascript:alert(1)\">", 376 | "<img src=x\\x10onerror=\"javascript:alert(1)\">", 377 | "<img src=x\\x11onerror=\"javascript:alert(1)\">", 378 | "<img src=x\\x12onerror=\"javascript:alert(1)\">", 379 | "<img src=x\\x13onerror=\"javascript:alert(1)\">", 380 | "<img[a][b][c]src[d]=x[e]onerror=[f]\"alert(1)\">", 381 | "<img src=x onerror=\\x09\"javascript:alert(1)\">", 382 | "<img src=x onerror=\\x10\"javascript:alert(1)\">", 383 | "<img src=x onerror=\\x11\"javascript:alert(1)\">", 384 | "<img src=x onerror=\\x12\"javascript:alert(1)\">", 385 | "<img src=x onerror=\\x32\"javascript:alert(1)\">", 386 | "<img src=x onerror=\\x00\"javascript:alert(1)\">", 387 | "<a href=java script:javascript:alert(1)>XXX</a>", 388 | "<img src=\"x` `<script>javascript:alert(1)</script>\"` `>", 389 | "<img src onerror /\" '\"= alt=javascript:alert(1)//\">", 390 | "<title onpropertychange=javascript:alert(1)>", 391 | "<a href=http://foo.bar/#x=`y></a><img alt=\"`><img src=x:x onerror=javascript:alert(1)></a>\">", 392 | "<!--[if]><script>javascript:alert(1)</script -->", 393 | "<!--[if<img src=x onerror=javascript:alert(1)//]> -->", 394 | "<script src=\"/\\%(jscript)s\"></script>", 395 | "<script src=\"\\\\%(jscript)s\"></script>", 396 | "<IMG \"\"\"><SCRIPT>alert(\"XSS\")</SCRIPT>\">", 397 | "<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>", 398 | "<IMG SRC=# onmouseover=\"alert('xxs')\">", 399 | "<IMG SRC= onmouseover=\"alert('xxs')\">", 400 | "<IMG onmouseover=\"alert('xxs')\">", 401 | "<IMG SRC=javascript:alert('XSS')>", 402 | "<IMG SRC=javascript:alert('XSS')>", 403 | "<IMG SRC=javascript:alert('XSS')>", 404 | "<IMG SRC=\"jav ascript:alert('XSS');\">", 405 | "<IMG SRC=\"jav ascript:alert('XSS');\">", 406 | "<IMG SRC=\"jav ascript:alert('XSS');\">", 407 | "<IMG SRC=\"jav ascript:alert('XSS');\">", 408 | "perl -e 'print \"<IMG SRC=java\\0script:alert(\\\"XSS\\\")>\";' > out", 409 | "<IMG SRC=\"  javascript:alert('XSS');\">", 410 | "<SCRIPT/XSS SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT>", 411 | "<BODY onload!#$%&()*~+-_.,:;?@[/|\\]^`=alert(\"XSS\")>", 412 | "<SCRIPT/SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT>", 413 | "<<SCRIPT>alert(\"XSS\");//<</SCRIPT>", 414 | "<SCRIPT SRC=http://ha.ckers.org/xss.js?< B >", 415 | "<SCRIPT SRC=//ha.ckers.org/.j>", 416 | "<IMG SRC=\"javascript:alert('XSS')\"", 417 | "<iframe src=http://ha.ckers.org/scriptlet.html <", 418 | "\\\";alert('XSS');//", 419 | "<u oncopy=alert()> Copy me</u>", 420 | "<i onwheel=alert(1)> Scroll over me </i>", 421 | "<plaintext>", 422 | "http://a/%%30%30", 423 | "</textarea><script>alert(123)</script>", 424 | "1;DROP TABLE users", 425 | "1'; DROP TABLE users-- 1", 426 | "' OR 1=1 -- 1", 427 | "' OR '1'='1", 428 | " ", 429 | "%", 430 | "_", 431 | "-", 432 | "--", 433 | "--version", 434 | "--help", 435 | "$USER", 436 | "/dev/null; touch /tmp/blns.fail ; echo", 437 | "`touch /tmp/blns.fail`", 438 | "$(touch /tmp/blns.fail)", 439 | "@{[system \"touch /tmp/blns.fail\"]}", 440 | "eval(\"puts 'hello world'\")", 441 | "System(\"ls -al /\")", 442 | "`ls -al /`", 443 | "Kernel.exec(\"ls -al /\")", 444 | "Kernel.exit(1)", 445 | "%x('ls -al /')", 446 | "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><!DOCTYPE foo [ <!ELEMENT foo ANY ><!ENTITY xxe SYSTEM \"file:///etc/passwd\" >]><foo>&xxe;</foo>", 447 | "$HOME", 448 | "$ENV{'HOME'}", 449 | "%d", 450 | "%s%s%s%s%s", 451 | "{0}", 452 | "%*.*s", 453 | "%@", 454 | "%n", 455 | "File:///", 456 | "../../../../../../../../../../../etc/passwd%00", 457 | "../../../../../../../../../../../etc/hosts", 458 | "() { 0; }; touch /tmp/blns.shellshock1.fail;", 459 | "() { _; } >_[$($())] { touch /tmp/blns.shellshock2.fail; }", 460 | "<<< %s(un='%s') = %u", 461 | "+++ATH0", 462 | "CON", 463 | "PRN", 464 | "AUX", 465 | "CLOCK$", 466 | "NUL", 467 | "A:", 468 | "ZZ:", 469 | "COM1", 470 | "LPT1", 471 | "LPT2", 472 | "LPT3", 473 | "COM2", 474 | "COM3", 475 | "COM4", 476 | "DCC SEND STARTKEYLOGGER 0 0 0", 477 | "Scunthorpe General Hospital", 478 | "Penistone Community Church", 479 | "Lightwater Country Park", 480 | "Jimmy Clitheroe", 481 | "Horniman Museum", 482 | "shitake mushrooms", 483 | "RomansInSussex.co.uk", 484 | "http://www.cum.qc.ca/", 485 | "Craig Cockburn, Software Specialist", 486 | "Linda Callahan", 487 | "Dr. Herman I. Libshitz", 488 | "magna cum laude", 489 | "Super Bowl XXX", 490 | "medieval erection of parapets", 491 | "evaluate", 492 | "mocha", 493 | "expression", 494 | "Arsenal canal", 495 | "classic", 496 | "Tyson Gay", 497 | "Dick Van Dyke", 498 | "basement", 499 | "If you're reading this, you've been in a coma for almost 20 years now. We're trying a new technique. We don't know where this message will end up in your dream, but we hope it works. Please wake up, we miss you.", 500 | "Roses are \u001b[0;31mred\u001b[0m, violets are \u001b[0;34mblue. Hope you enjoy terminal hue", 501 | "But now...\u001b[20Cfor my greatest trick...\u001b[8m", 502 | "The quic\b\b\b\b\b\bk brown fo\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007x... [Beeeep]", 503 | "Powerلُلُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ冗", 504 | "🏳0🌈️", 505 | "జ్ఞ‌ా" 506 | ] -------------------------------------------------------------------------------- /src/test/kotlin/com/tylerthrailkill/helpers/prettyprint/MassiveObjectTest.kt: -------------------------------------------------------------------------------- 1 | package com.tylerthrailkill.helpers.prettyprint 2 | 3 | import io.kotest.core.spec.style.FreeSpec 4 | import java.math.BigDecimal 5 | import java.util.UUID 6 | 7 | class MassiveObjectTest : FreeSpec({ 8 | 9 | "massive objects" - { 10 | val smallObject = SmallObject("a string in small object", 777) 11 | val nestedLargeObjectNull = NestedLargeObject( 12 | NestedSmallObject(smallObject), 13 | smallObject, 14 | "test string, please don't break", 15 | null 16 | ) 17 | val nestedLargeObject = NestedLargeObject( 18 | NestedSmallObject(smallObject), 19 | smallObject, 20 | "test string, please don't break", 21 | NestedLargeObject( 22 | NestedSmallObject(smallObject), 23 | smallObject, 24 | "test string, please don't break", 25 | nestedLargeObjectNull 26 | ) 27 | ) 28 | val emailList = mutableListOf( 29 | EmailAddress("a@b.com"), 30 | EmailAddress("\uD83C\uDF83@zack.is"), 31 | EmailAddress("ñoñó1234@server.com"), 32 | EmailAddress("δοκιμή@παράδειγμα.δοκιμή"), 33 | EmailAddress("我買@屋企.香港"), 34 | EmailAddress("二ノ宮@黒川.日本"), 35 | EmailAddress("чебурашка@ящик-с-апельсинами.рф"), 36 | EmailAddress("संपर्क@डाटामेल.भारत"), 37 | EmailAddress("simple@example.com"), 38 | EmailAddress("very.common@example.com"), 39 | EmailAddress("disposable.style.email.with+symbol@example.com"), 40 | EmailAddress("other.email-with-hyphen@example.com"), 41 | EmailAddress("fully-qualified-domain@example.com"), 42 | EmailAddress("user.name+tag+sorting@example.com"), 43 | EmailAddress("x@example.com"), 44 | EmailAddress("example-indeed@strange-example.com"), 45 | EmailAddress("admin@mailserver1"), 46 | EmailAddress("example@s.example"), 47 | EmailAddress("\" \"@example.org"), 48 | EmailAddress("\"john..doe\"@example.org") 49 | ) 50 | "should render" - { 51 | // DON'T INDENT THIS STRING. IT'S TOO LARGE FOR THE JVM 😂😂😂 52 | prettyPrint( 53 | MassiveObject( 54 | "a string", 55 | mutableListOf( 56 | AValueObject( 57 | UUID.fromString("b2558c12-d4d3-4abd-94e4-8600902f1edf"), 58 | BigDecimal.ONE, 59 | emailList, 60 | listOf( 61 | mapOf( 62 | "a" to nestedLargeObject, 63 | "b" to nestedLargeObject, 64 | "c" to nestedLargeObject 65 | ), 66 | mapOf( 67 | "d" to nestedLargeObject, 68 | "e" to nestedLargeObject, 69 | "f" to nestedLargeObject 70 | ), 71 | mapOf( 72 | "g" to nestedLargeObject, 73 | "h" to nestedLargeObject, 74 | "i" to nestedLargeObject 75 | ) 76 | ), 77 | mapOf( 78 | "listA" to listOf( 79 | nestedLargeObject, 80 | nestedLargeObject, 81 | nestedLargeObject 82 | ), 83 | "listB" to listOf( 84 | nestedLargeObject, 85 | nestedLargeObject, 86 | nestedLargeObject 87 | ), 88 | "listC" to listOf( 89 | nestedLargeObject, 90 | nestedLargeObject, 91 | nestedLargeObject 92 | ) 93 | ) 94 | ) 95 | ) 96 | ) 97 | ) mapTo """ 98 | MassiveObject( 99 | astring = "a string" 100 | listOfObject = [ 101 | AValueObject( 102 | uuid = b2558c12-d4d3-4abd-94e4-8600902f1edf 103 | number = 1 104 | emailAddresses = [ 105 | EmailAddress( 106 | emailAddress = "a@b.com" 107 | serialVersionUUID = 1 108 | ), 109 | EmailAddress( 110 | emailAddress = "🎃@zack.is" 111 | serialVersionUUID = 1 112 | ), 113 | EmailAddress( 114 | emailAddress = "ñoñó1234@server.com" 115 | serialVersionUUID = 1 116 | ), 117 | EmailAddress( 118 | emailAddress = "δοκιμή@παράδειγμα.δοκιμή" 119 | serialVersionUUID = 1 120 | ), 121 | EmailAddress( 122 | emailAddress = "我買@屋企.香港" 123 | serialVersionUUID = 1 124 | ), 125 | EmailAddress( 126 | emailAddress = "二ノ宮@黒川.日本" 127 | serialVersionUUID = 1 128 | ), 129 | EmailAddress( 130 | emailAddress = "чебурашка@ящик-с-апельсинами.рф" 131 | serialVersionUUID = 1 132 | ), 133 | EmailAddress( 134 | emailAddress = "संपर्क@डाटामेल.भारत" 135 | serialVersionUUID = 1 136 | ), 137 | EmailAddress( 138 | emailAddress = "simple@example.com" 139 | serialVersionUUID = 1 140 | ), 141 | EmailAddress( 142 | emailAddress = "very.common@example.com" 143 | serialVersionUUID = 1 144 | ), 145 | EmailAddress( 146 | emailAddress = "disposable.style.email.with+symbol@example.com" 147 | serialVersionUUID = 1 148 | ), 149 | EmailAddress( 150 | emailAddress = "other.email-with-hyphen@example.com" 151 | serialVersionUUID = 1 152 | ), 153 | EmailAddress( 154 | emailAddress = "fully-qualified-domain@example.com" 155 | serialVersionUUID = 1 156 | ), 157 | EmailAddress( 158 | emailAddress = "user.name+tag+sorting@example.com" 159 | serialVersionUUID = 1 160 | ), 161 | EmailAddress( 162 | emailAddress = "x@example.com" 163 | serialVersionUUID = 1 164 | ), 165 | EmailAddress( 166 | emailAddress = "example-indeed@strange-example.com" 167 | serialVersionUUID = 1 168 | ), 169 | EmailAddress( 170 | emailAddress = "admin@mailserver1" 171 | serialVersionUUID = 1 172 | ), 173 | EmailAddress( 174 | emailAddress = "example@s.example" 175 | serialVersionUUID = 1 176 | ), 177 | EmailAddress( 178 | emailAddress = "" "@example.org" 179 | serialVersionUUID = 1 180 | ), 181 | EmailAddress( 182 | emailAddress = ""john..doe"@example.org" 183 | serialVersionUUID = 1 184 | ) 185 | ] 186 | nestedObjectsListToMap = [ 187 | { 188 | "a" -> NestedLargeObject( 189 | nestedSmallObject = NestedSmallObject( 190 | smallObject = SmallObject( 191 | field1 = "a string in small object" 192 | field2 = 777 193 | ) 194 | ) 195 | smallObject = SmallObject( 196 | field1 = "a string in small object" 197 | field2 = 777 198 | ) 199 | testString = "test string, please don't break" 200 | bigObject = NestedLargeObject( 201 | nestedSmallObject = NestedSmallObject( 202 | smallObject = SmallObject( 203 | field1 = "a string in small object" 204 | field2 = 777 205 | ) 206 | ) 207 | smallObject = SmallObject( 208 | field1 = "a string in small object" 209 | field2 = 777 210 | ) 211 | testString = "test string, please don't break" 212 | bigObject = NestedLargeObject( 213 | nestedSmallObject = NestedSmallObject( 214 | smallObject = SmallObject( 215 | field1 = "a string in small object" 216 | field2 = 777 217 | ) 218 | ) 219 | smallObject = SmallObject( 220 | field1 = "a string in small object" 221 | field2 = 777 222 | ) 223 | testString = "test string, please don't break" 224 | bigObject = null 225 | ) 226 | ) 227 | ), 228 | "b" -> NestedLargeObject( 229 | nestedSmallObject = NestedSmallObject( 230 | smallObject = SmallObject( 231 | field1 = "a string in small object" 232 | field2 = 777 233 | ) 234 | ) 235 | smallObject = SmallObject( 236 | field1 = "a string in small object" 237 | field2 = 777 238 | ) 239 | testString = "test string, please don't break" 240 | bigObject = NestedLargeObject( 241 | nestedSmallObject = NestedSmallObject( 242 | smallObject = SmallObject( 243 | field1 = "a string in small object" 244 | field2 = 777 245 | ) 246 | ) 247 | smallObject = SmallObject( 248 | field1 = "a string in small object" 249 | field2 = 777 250 | ) 251 | testString = "test string, please don't break" 252 | bigObject = NestedLargeObject( 253 | nestedSmallObject = NestedSmallObject( 254 | smallObject = SmallObject( 255 | field1 = "a string in small object" 256 | field2 = 777 257 | ) 258 | ) 259 | smallObject = SmallObject( 260 | field1 = "a string in small object" 261 | field2 = 777 262 | ) 263 | testString = "test string, please don't break" 264 | bigObject = null 265 | ) 266 | ) 267 | ), 268 | "c" -> NestedLargeObject( 269 | nestedSmallObject = NestedSmallObject( 270 | smallObject = SmallObject( 271 | field1 = "a string in small object" 272 | field2 = 777 273 | ) 274 | ) 275 | smallObject = SmallObject( 276 | field1 = "a string in small object" 277 | field2 = 777 278 | ) 279 | testString = "test string, please don't break" 280 | bigObject = NestedLargeObject( 281 | nestedSmallObject = NestedSmallObject( 282 | smallObject = SmallObject( 283 | field1 = "a string in small object" 284 | field2 = 777 285 | ) 286 | ) 287 | smallObject = SmallObject( 288 | field1 = "a string in small object" 289 | field2 = 777 290 | ) 291 | testString = "test string, please don't break" 292 | bigObject = NestedLargeObject( 293 | nestedSmallObject = NestedSmallObject( 294 | smallObject = SmallObject( 295 | field1 = "a string in small object" 296 | field2 = 777 297 | ) 298 | ) 299 | smallObject = SmallObject( 300 | field1 = "a string in small object" 301 | field2 = 777 302 | ) 303 | testString = "test string, please don't break" 304 | bigObject = null 305 | ) 306 | ) 307 | ) 308 | }, 309 | { 310 | "d" -> NestedLargeObject( 311 | nestedSmallObject = NestedSmallObject( 312 | smallObject = SmallObject( 313 | field1 = "a string in small object" 314 | field2 = 777 315 | ) 316 | ) 317 | smallObject = SmallObject( 318 | field1 = "a string in small object" 319 | field2 = 777 320 | ) 321 | testString = "test string, please don't break" 322 | bigObject = NestedLargeObject( 323 | nestedSmallObject = NestedSmallObject( 324 | smallObject = SmallObject( 325 | field1 = "a string in small object" 326 | field2 = 777 327 | ) 328 | ) 329 | smallObject = SmallObject( 330 | field1 = "a string in small object" 331 | field2 = 777 332 | ) 333 | testString = "test string, please don't break" 334 | bigObject = NestedLargeObject( 335 | nestedSmallObject = NestedSmallObject( 336 | smallObject = SmallObject( 337 | field1 = "a string in small object" 338 | field2 = 777 339 | ) 340 | ) 341 | smallObject = SmallObject( 342 | field1 = "a string in small object" 343 | field2 = 777 344 | ) 345 | testString = "test string, please don't break" 346 | bigObject = null 347 | ) 348 | ) 349 | ), 350 | "e" -> NestedLargeObject( 351 | nestedSmallObject = NestedSmallObject( 352 | smallObject = SmallObject( 353 | field1 = "a string in small object" 354 | field2 = 777 355 | ) 356 | ) 357 | smallObject = SmallObject( 358 | field1 = "a string in small object" 359 | field2 = 777 360 | ) 361 | testString = "test string, please don't break" 362 | bigObject = NestedLargeObject( 363 | nestedSmallObject = NestedSmallObject( 364 | smallObject = SmallObject( 365 | field1 = "a string in small object" 366 | field2 = 777 367 | ) 368 | ) 369 | smallObject = SmallObject( 370 | field1 = "a string in small object" 371 | field2 = 777 372 | ) 373 | testString = "test string, please don't break" 374 | bigObject = NestedLargeObject( 375 | nestedSmallObject = NestedSmallObject( 376 | smallObject = SmallObject( 377 | field1 = "a string in small object" 378 | field2 = 777 379 | ) 380 | ) 381 | smallObject = SmallObject( 382 | field1 = "a string in small object" 383 | field2 = 777 384 | ) 385 | testString = "test string, please don't break" 386 | bigObject = null 387 | ) 388 | ) 389 | ), 390 | "f" -> NestedLargeObject( 391 | nestedSmallObject = NestedSmallObject( 392 | smallObject = SmallObject( 393 | field1 = "a string in small object" 394 | field2 = 777 395 | ) 396 | ) 397 | smallObject = SmallObject( 398 | field1 = "a string in small object" 399 | field2 = 777 400 | ) 401 | testString = "test string, please don't break" 402 | bigObject = NestedLargeObject( 403 | nestedSmallObject = NestedSmallObject( 404 | smallObject = SmallObject( 405 | field1 = "a string in small object" 406 | field2 = 777 407 | ) 408 | ) 409 | smallObject = SmallObject( 410 | field1 = "a string in small object" 411 | field2 = 777 412 | ) 413 | testString = "test string, please don't break" 414 | bigObject = NestedLargeObject( 415 | nestedSmallObject = NestedSmallObject( 416 | smallObject = SmallObject( 417 | field1 = "a string in small object" 418 | field2 = 777 419 | ) 420 | ) 421 | smallObject = SmallObject( 422 | field1 = "a string in small object" 423 | field2 = 777 424 | ) 425 | testString = "test string, please don't break" 426 | bigObject = null 427 | ) 428 | ) 429 | ) 430 | }, 431 | { 432 | "g" -> NestedLargeObject( 433 | nestedSmallObject = NestedSmallObject( 434 | smallObject = SmallObject( 435 | field1 = "a string in small object" 436 | field2 = 777 437 | ) 438 | ) 439 | smallObject = SmallObject( 440 | field1 = "a string in small object" 441 | field2 = 777 442 | ) 443 | testString = "test string, please don't break" 444 | bigObject = NestedLargeObject( 445 | nestedSmallObject = NestedSmallObject( 446 | smallObject = SmallObject( 447 | field1 = "a string in small object" 448 | field2 = 777 449 | ) 450 | ) 451 | smallObject = SmallObject( 452 | field1 = "a string in small object" 453 | field2 = 777 454 | ) 455 | testString = "test string, please don't break" 456 | bigObject = NestedLargeObject( 457 | nestedSmallObject = NestedSmallObject( 458 | smallObject = SmallObject( 459 | field1 = "a string in small object" 460 | field2 = 777 461 | ) 462 | ) 463 | smallObject = SmallObject( 464 | field1 = "a string in small object" 465 | field2 = 777 466 | ) 467 | testString = "test string, please don't break" 468 | bigObject = null 469 | ) 470 | ) 471 | ), 472 | "h" -> NestedLargeObject( 473 | nestedSmallObject = NestedSmallObject( 474 | smallObject = SmallObject( 475 | field1 = "a string in small object" 476 | field2 = 777 477 | ) 478 | ) 479 | smallObject = SmallObject( 480 | field1 = "a string in small object" 481 | field2 = 777 482 | ) 483 | testString = "test string, please don't break" 484 | bigObject = NestedLargeObject( 485 | nestedSmallObject = NestedSmallObject( 486 | smallObject = SmallObject( 487 | field1 = "a string in small object" 488 | field2 = 777 489 | ) 490 | ) 491 | smallObject = SmallObject( 492 | field1 = "a string in small object" 493 | field2 = 777 494 | ) 495 | testString = "test string, please don't break" 496 | bigObject = NestedLargeObject( 497 | nestedSmallObject = NestedSmallObject( 498 | smallObject = SmallObject( 499 | field1 = "a string in small object" 500 | field2 = 777 501 | ) 502 | ) 503 | smallObject = SmallObject( 504 | field1 = "a string in small object" 505 | field2 = 777 506 | ) 507 | testString = "test string, please don't break" 508 | bigObject = null 509 | ) 510 | ) 511 | ), 512 | "i" -> NestedLargeObject( 513 | nestedSmallObject = NestedSmallObject( 514 | smallObject = SmallObject( 515 | field1 = "a string in small object" 516 | field2 = 777 517 | ) 518 | ) 519 | smallObject = SmallObject( 520 | field1 = "a string in small object" 521 | field2 = 777 522 | ) 523 | testString = "test string, please don't break" 524 | bigObject = NestedLargeObject( 525 | nestedSmallObject = NestedSmallObject( 526 | smallObject = SmallObject( 527 | field1 = "a string in small object" 528 | field2 = 777 529 | ) 530 | ) 531 | smallObject = SmallObject( 532 | field1 = "a string in small object" 533 | field2 = 777 534 | ) 535 | testString = "test string, please don't break" 536 | bigObject = NestedLargeObject( 537 | nestedSmallObject = NestedSmallObject( 538 | smallObject = SmallObject( 539 | field1 = "a string in small object" 540 | field2 = 777 541 | ) 542 | ) 543 | smallObject = SmallObject( 544 | field1 = "a string in small object" 545 | field2 = 777 546 | ) 547 | testString = "test string, please don't break" 548 | bigObject = null 549 | ) 550 | ) 551 | ) 552 | } 553 | ] 554 | nestedObjectsMapToList = { 555 | "listA" -> [ 556 | NestedLargeObject( 557 | nestedSmallObject = NestedSmallObject( 558 | smallObject = SmallObject( 559 | field1 = "a string in small object" 560 | field2 = 777 561 | ) 562 | ) 563 | smallObject = SmallObject( 564 | field1 = "a string in small object" 565 | field2 = 777 566 | ) 567 | testString = "test string, please don't break" 568 | bigObject = NestedLargeObject( 569 | nestedSmallObject = NestedSmallObject( 570 | smallObject = SmallObject( 571 | field1 = "a string in small object" 572 | field2 = 777 573 | ) 574 | ) 575 | smallObject = SmallObject( 576 | field1 = "a string in small object" 577 | field2 = 777 578 | ) 579 | testString = "test string, please don't break" 580 | bigObject = NestedLargeObject( 581 | nestedSmallObject = NestedSmallObject( 582 | smallObject = SmallObject( 583 | field1 = "a string in small object" 584 | field2 = 777 585 | ) 586 | ) 587 | smallObject = SmallObject( 588 | field1 = "a string in small object" 589 | field2 = 777 590 | ) 591 | testString = "test string, please don't break" 592 | bigObject = null 593 | ) 594 | ) 595 | ), 596 | NestedLargeObject( 597 | nestedSmallObject = NestedSmallObject( 598 | smallObject = SmallObject( 599 | field1 = "a string in small object" 600 | field2 = 777 601 | ) 602 | ) 603 | smallObject = SmallObject( 604 | field1 = "a string in small object" 605 | field2 = 777 606 | ) 607 | testString = "test string, please don't break" 608 | bigObject = NestedLargeObject( 609 | nestedSmallObject = NestedSmallObject( 610 | smallObject = SmallObject( 611 | field1 = "a string in small object" 612 | field2 = 777 613 | ) 614 | ) 615 | smallObject = SmallObject( 616 | field1 = "a string in small object" 617 | field2 = 777 618 | ) 619 | testString = "test string, please don't break" 620 | bigObject = NestedLargeObject( 621 | nestedSmallObject = NestedSmallObject( 622 | smallObject = SmallObject( 623 | field1 = "a string in small object" 624 | field2 = 777 625 | ) 626 | ) 627 | smallObject = SmallObject( 628 | field1 = "a string in small object" 629 | field2 = 777 630 | ) 631 | testString = "test string, please don't break" 632 | bigObject = null 633 | ) 634 | ) 635 | ), 636 | NestedLargeObject( 637 | nestedSmallObject = NestedSmallObject( 638 | smallObject = SmallObject( 639 | field1 = "a string in small object" 640 | field2 = 777 641 | ) 642 | ) 643 | smallObject = SmallObject( 644 | field1 = "a string in small object" 645 | field2 = 777 646 | ) 647 | testString = "test string, please don't break" 648 | bigObject = NestedLargeObject( 649 | nestedSmallObject = NestedSmallObject( 650 | smallObject = SmallObject( 651 | field1 = "a string in small object" 652 | field2 = 777 653 | ) 654 | ) 655 | smallObject = SmallObject( 656 | field1 = "a string in small object" 657 | field2 = 777 658 | ) 659 | testString = "test string, please don't break" 660 | bigObject = NestedLargeObject( 661 | nestedSmallObject = NestedSmallObject( 662 | smallObject = SmallObject( 663 | field1 = "a string in small object" 664 | field2 = 777 665 | ) 666 | ) 667 | smallObject = SmallObject( 668 | field1 = "a string in small object" 669 | field2 = 777 670 | ) 671 | testString = "test string, please don't break" 672 | bigObject = null 673 | ) 674 | ) 675 | ) 676 | ], 677 | "listB" -> [ 678 | NestedLargeObject( 679 | nestedSmallObject = NestedSmallObject( 680 | smallObject = SmallObject( 681 | field1 = "a string in small object" 682 | field2 = 777 683 | ) 684 | ) 685 | smallObject = SmallObject( 686 | field1 = "a string in small object" 687 | field2 = 777 688 | ) 689 | testString = "test string, please don't break" 690 | bigObject = NestedLargeObject( 691 | nestedSmallObject = NestedSmallObject( 692 | smallObject = SmallObject( 693 | field1 = "a string in small object" 694 | field2 = 777 695 | ) 696 | ) 697 | smallObject = SmallObject( 698 | field1 = "a string in small object" 699 | field2 = 777 700 | ) 701 | testString = "test string, please don't break" 702 | bigObject = NestedLargeObject( 703 | nestedSmallObject = NestedSmallObject( 704 | smallObject = SmallObject( 705 | field1 = "a string in small object" 706 | field2 = 777 707 | ) 708 | ) 709 | smallObject = SmallObject( 710 | field1 = "a string in small object" 711 | field2 = 777 712 | ) 713 | testString = "test string, please don't break" 714 | bigObject = null 715 | ) 716 | ) 717 | ), 718 | NestedLargeObject( 719 | nestedSmallObject = NestedSmallObject( 720 | smallObject = SmallObject( 721 | field1 = "a string in small object" 722 | field2 = 777 723 | ) 724 | ) 725 | smallObject = SmallObject( 726 | field1 = "a string in small object" 727 | field2 = 777 728 | ) 729 | testString = "test string, please don't break" 730 | bigObject = NestedLargeObject( 731 | nestedSmallObject = NestedSmallObject( 732 | smallObject = SmallObject( 733 | field1 = "a string in small object" 734 | field2 = 777 735 | ) 736 | ) 737 | smallObject = SmallObject( 738 | field1 = "a string in small object" 739 | field2 = 777 740 | ) 741 | testString = "test string, please don't break" 742 | bigObject = NestedLargeObject( 743 | nestedSmallObject = NestedSmallObject( 744 | smallObject = SmallObject( 745 | field1 = "a string in small object" 746 | field2 = 777 747 | ) 748 | ) 749 | smallObject = SmallObject( 750 | field1 = "a string in small object" 751 | field2 = 777 752 | ) 753 | testString = "test string, please don't break" 754 | bigObject = null 755 | ) 756 | ) 757 | ), 758 | NestedLargeObject( 759 | nestedSmallObject = NestedSmallObject( 760 | smallObject = SmallObject( 761 | field1 = "a string in small object" 762 | field2 = 777 763 | ) 764 | ) 765 | smallObject = SmallObject( 766 | field1 = "a string in small object" 767 | field2 = 777 768 | ) 769 | testString = "test string, please don't break" 770 | bigObject = NestedLargeObject( 771 | nestedSmallObject = NestedSmallObject( 772 | smallObject = SmallObject( 773 | field1 = "a string in small object" 774 | field2 = 777 775 | ) 776 | ) 777 | smallObject = SmallObject( 778 | field1 = "a string in small object" 779 | field2 = 777 780 | ) 781 | testString = "test string, please don't break" 782 | bigObject = NestedLargeObject( 783 | nestedSmallObject = NestedSmallObject( 784 | smallObject = SmallObject( 785 | field1 = "a string in small object" 786 | field2 = 777 787 | ) 788 | ) 789 | smallObject = SmallObject( 790 | field1 = "a string in small object" 791 | field2 = 777 792 | ) 793 | testString = "test string, please don't break" 794 | bigObject = null 795 | ) 796 | ) 797 | ) 798 | ], 799 | "listC" -> [ 800 | NestedLargeObject( 801 | nestedSmallObject = NestedSmallObject( 802 | smallObject = SmallObject( 803 | field1 = "a string in small object" 804 | field2 = 777 805 | ) 806 | ) 807 | smallObject = SmallObject( 808 | field1 = "a string in small object" 809 | field2 = 777 810 | ) 811 | testString = "test string, please don't break" 812 | bigObject = NestedLargeObject( 813 | nestedSmallObject = NestedSmallObject( 814 | smallObject = SmallObject( 815 | field1 = "a string in small object" 816 | field2 = 777 817 | ) 818 | ) 819 | smallObject = SmallObject( 820 | field1 = "a string in small object" 821 | field2 = 777 822 | ) 823 | testString = "test string, please don't break" 824 | bigObject = NestedLargeObject( 825 | nestedSmallObject = NestedSmallObject( 826 | smallObject = SmallObject( 827 | field1 = "a string in small object" 828 | field2 = 777 829 | ) 830 | ) 831 | smallObject = SmallObject( 832 | field1 = "a string in small object" 833 | field2 = 777 834 | ) 835 | testString = "test string, please don't break" 836 | bigObject = null 837 | ) 838 | ) 839 | ), 840 | NestedLargeObject( 841 | nestedSmallObject = NestedSmallObject( 842 | smallObject = SmallObject( 843 | field1 = "a string in small object" 844 | field2 = 777 845 | ) 846 | ) 847 | smallObject = SmallObject( 848 | field1 = "a string in small object" 849 | field2 = 777 850 | ) 851 | testString = "test string, please don't break" 852 | bigObject = NestedLargeObject( 853 | nestedSmallObject = NestedSmallObject( 854 | smallObject = SmallObject( 855 | field1 = "a string in small object" 856 | field2 = 777 857 | ) 858 | ) 859 | smallObject = SmallObject( 860 | field1 = "a string in small object" 861 | field2 = 777 862 | ) 863 | testString = "test string, please don't break" 864 | bigObject = NestedLargeObject( 865 | nestedSmallObject = NestedSmallObject( 866 | smallObject = SmallObject( 867 | field1 = "a string in small object" 868 | field2 = 777 869 | ) 870 | ) 871 | smallObject = SmallObject( 872 | field1 = "a string in small object" 873 | field2 = 777 874 | ) 875 | testString = "test string, please don't break" 876 | bigObject = null 877 | ) 878 | ) 879 | ), 880 | NestedLargeObject( 881 | nestedSmallObject = NestedSmallObject( 882 | smallObject = SmallObject( 883 | field1 = "a string in small object" 884 | field2 = 777 885 | ) 886 | ) 887 | smallObject = SmallObject( 888 | field1 = "a string in small object" 889 | field2 = 777 890 | ) 891 | testString = "test string, please don't break" 892 | bigObject = NestedLargeObject( 893 | nestedSmallObject = NestedSmallObject( 894 | smallObject = SmallObject( 895 | field1 = "a string in small object" 896 | field2 = 777 897 | ) 898 | ) 899 | smallObject = SmallObject( 900 | field1 = "a string in small object" 901 | field2 = 777 902 | ) 903 | testString = "test string, please don't break" 904 | bigObject = NestedLargeObject( 905 | nestedSmallObject = NestedSmallObject( 906 | smallObject = SmallObject( 907 | field1 = "a string in small object" 908 | field2 = 777 909 | ) 910 | ) 911 | smallObject = SmallObject( 912 | field1 = "a string in small object" 913 | field2 = 777 914 | ) 915 | testString = "test string, please don't break" 916 | bigObject = null 917 | ) 918 | ) 919 | ) 920 | ] 921 | } 922 | ) 923 | ] 924 | ) 925 | """ 926 | } 927 | } 928 | }) 929 | --------------------------------------------------------------------------------