diff --git a/README.md b/README.md index 72aff7e7..71588ceb 100644 --- a/README.md +++ b/README.md @@ -76,18 +76,18 @@ Maven: com.simiacryptus skyenet-webui - 1.0.61 + 1.0.62 ``` Gradle: ```groovy -implementation group: 'com.simiacryptus', name: 'skyenet', version: '1.0.61' +implementation group: 'com.simiacryptus', name: 'skyenet', version: '1.0.62' ``` ```kotlin -implementation("com.simiacryptus:skyenet:1.0.61") +implementation("com.simiacryptus:skyenet:1.0.62") ``` ### 🌟 To Use diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 6df61c63..5cbc4e01 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -33,7 +33,7 @@ val hsqldb_version = "2.7.2" dependencies { - implementation(group = "com.simiacryptus", name = "jo-penai", version = "1.0.61") + implementation(group = "com.simiacryptus", name = "jo-penai", version = "1.0.62") implementation(group = "org.hsqldb", name = "hsqldb", version = hsqldb_version) implementation("org.apache.commons:commons-text:1.11.0") diff --git a/gradle.properties b/gradle.properties index 190aaf72..4311554e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ # Gradle Releases -> https://github.com/gradle/gradle/releases libraryGroup = com.simiacryptus.skyenet -libraryVersion = 1.0.78 +libraryVersion = 1.0.79 gradleVersion = 7.6.1 diff --git a/webui/build.gradle.kts b/webui/build.gradle.kts index 41464b9b..2a3d1caa 100644 --- a/webui/build.gradle.kts +++ b/webui/build.gradle.kts @@ -35,7 +35,7 @@ val jetty_version = "11.0.18" val jackson_version = "2.17.0" dependencies { - implementation(group = "com.simiacryptus", name = "jo-penai", version = "1.0.61") + implementation(group = "com.simiacryptus", name = "jo-penai", version = "1.0.62") implementation(project(":core")) implementation(project(":kotlin")) diff --git a/webui/src/main/kotlin/com/simiacryptus/diff/AddSaveLinks.kt b/webui/src/main/kotlin/com/simiacryptus/diff/AddSaveLinks.kt index d0410cdf..d6c82ff7 100644 --- a/webui/src/main/kotlin/com/simiacryptus/diff/AddSaveLinks.kt +++ b/webui/src/main/kotlin/com/simiacryptus/diff/AddSaveLinks.kt @@ -13,11 +13,7 @@ fun SocketManagerBase.addSaveLinks( ui: ApplicationInterface, handle: (Path, String) -> Unit, ): String { - val diffPattern = - """(?s)(? val filename = extractFilename(diffBlock.groupValues[1]) diff --git a/webui/src/main/kotlin/com/simiacryptus/diff/DiffUtil.kt b/webui/src/main/kotlin/com/simiacryptus/diff/DiffUtil.kt index 2c703e27..39893447 100644 --- a/webui/src/main/kotlin/com/simiacryptus/diff/DiffUtil.kt +++ b/webui/src/main/kotlin/com/simiacryptus/diff/DiffUtil.kt @@ -37,55 +37,65 @@ object DiffUtil { * @return A list of DiffResult indicating the differences. */ fun generateDiff(original: List, modified: List): List { - if (original == modified) return modified.withIndex().map { (i, v) -> PatchLine(Unchanged, i, v) } - val original = original.withIndex().map { (i, v) -> PatchLine(Unchanged, i, v) }.toMutableList() - val modified = modified.withIndex().map { (i, v) -> PatchLine(Unchanged, i, v) }.toMutableList() + val originalLines = original.withIndex().map { (i, v) -> PatchLine(Unchanged, i, v) } + val modifiedLines = modified.withIndex().map { (i, v) -> PatchLine(Unchanged, i, v) } val patchLines = mutableListOf() + var i = 0 + var j = 0 - while (original.isNotEmpty() && modified.isNotEmpty()) { - val originalLine = original.first() - val modifiedLine = modified.first() + while (i < originalLines.size && j < modifiedLines.size) { + val originalLine = originalLines[i] + val modifiedLine = modifiedLines[j] if (originalLine == modifiedLine) { patchLines.add(PatchLine(Unchanged, originalLine.lineNumber, originalLine.line)) - original.removeAt(0) - modified.removeAt(0) + i++ + j++ } else { - val originalIndex = original.indexOf(modifiedLine).let { if (it == -1) null else it } - val modifiedIndex = modified.indexOf(originalLine).let { if (it == -1) null else it } + val originalIndex = originalLines.subList(i, originalLines.size).indexOf(modifiedLine).let { if (it == -1) null else it + i } + val modifiedIndex = modifiedLines.subList(j, modifiedLines.size).indexOf(originalLine).let { if (it == -1) null else it + j } if (originalIndex != null && modifiedIndex != null) { if (originalIndex < modifiedIndex) { - while (original.first() != modifiedLine) { - patchLines.add(PatchLine(Deleted, original.first().lineNumber, original.first().line)) - original.removeAt(0) + while (i < originalIndex) { + patchLines.add(PatchLine(Deleted, originalLines[i].lineNumber, originalLines[i].line)) + i++ } } else { - while (modified.first() != originalLine) { - patchLines.add(PatchLine(Added, modified.first().lineNumber, modified.first().line)) - modified.removeAt(0) + while (j < modifiedIndex) { + patchLines.add(PatchLine(Added, modifiedLines[j].lineNumber, modifiedLines[j].line)) + j++ } } } else if (originalIndex != null) { - while (original.first() != modifiedLine) { - patchLines.add(PatchLine(Deleted, original.first().lineNumber, original.first().line)) - original.removeAt(0) + while (i < originalIndex) { + patchLines.add(PatchLine(Deleted, originalLines[i].lineNumber, originalLines[i].line)) + i++ } } else if (modifiedIndex != null) { - while (modified.first() != originalLine) { - patchLines.add(PatchLine(Added, modified.first().lineNumber, modified.first().line)) - modified.removeAt(0) + while (j < modifiedIndex) { + patchLines.add(PatchLine(Added, modifiedLines[j].lineNumber, modifiedLines[j].line)) + j++ } } else { - patchLines.add(PatchLine(Deleted, originalLine.lineNumber, originalLine.line)) - original.removeAt(0) - patchLines.add(PatchLine(Added, modifiedLine.lineNumber, modifiedLine.line)) - modified.removeAt(0) + patchLines.add(PatchLine(Deleted, originalLines[i].lineNumber, originalLines[i].line)) + patchLines.add(PatchLine(Added, modifiedLines[j].lineNumber, modifiedLines[j].line)) + i++ + j++ } } } - patchLines.addAll(original.map { PatchLine(Deleted, it.lineNumber, it.line) }) - patchLines.addAll(modified.map { PatchLine(Added, it.lineNumber, it.line) }) + + while (i < originalLines.size) { + patchLines.add(PatchLine(Deleted, originalLines[i].lineNumber, originalLines[i].line)) + i++ + } + + while (j < modifiedLines.size) { + patchLines.add(PatchLine(Added, modifiedLines[j].lineNumber, modifiedLines[j].line)) + j++ + } + return patchLines } @@ -99,32 +109,43 @@ object DiffUtil { * @return A formatted string representing the diff. */ fun formatDiff(patchLines: List, contextLines: Int = 3): String { - val patchList = patchLines.withIndex().filter { (idx, lineDiff) -> + val patchList = mutableListOf() + var inChange = false + var changeStart = 0 + var changeEnd = 0 + + patchLines.forEachIndexed { idx, lineDiff -> when (lineDiff.type) { - Added -> true - Deleted -> true + Added, Deleted -> { + if (!inChange) { + inChange = true + changeStart = maxOf(0, idx - contextLines) + patchList.addAll(patchLines.subList(changeStart, idx).filter { it.type == Unchanged }) + } + changeEnd = minOf(patchLines.size, idx + contextLines + 1) + patchList.add(lineDiff) + } Unchanged -> { - val distBackwards = - patchLines.subList(0, idx).indexOfLast { it.type != Unchanged } - .let { if (it == -1) null else idx - it } - val distForwards = patchLines.subList(idx, patchLines.size).indexOfFirst { it.type != Unchanged } - .let { if (it == -1) null else it } - (null != distBackwards && distBackwards <= contextLines) || (null != distForwards && distForwards <= contextLines) + if (inChange) { + if (idx >= changeEnd) { + inChange = false + patchList.addAll(patchLines.subList(maxOf(changeEnd, idx - contextLines), idx)) + } + } } } - }.map { it.value }.toTypedArray() + } + + if (inChange) { + patchList.addAll(patchLines.subList(maxOf(changeEnd - contextLines, patchList.size), minOf(changeEnd, patchLines.size))) + } - return patchList.withIndex().joinToString("\n") { (idx, lineDiff) -> - when { - idx == 0 -> "" - lineDiff.type != Unchanged || patchList[idx - 1].type != Unchanged -> "" - patchList[idx - 1].lineNumber + 1 < lineDiff.lineNumber -> "...\n" - else -> "" - } + when (lineDiff.type) { + return patchList.joinToString("\n") { lineDiff -> + when (lineDiff.type) { Added -> "+ ${lineDiff.line}" Deleted -> "- ${lineDiff.line}" Unchanged -> " ${lineDiff.line}" } } } -} +} \ No newline at end of file diff --git a/webui/src/main/kotlin/com/simiacryptus/diff/IterativePatchUtil.kt b/webui/src/main/kotlin/com/simiacryptus/diff/IterativePatchUtil.kt index ed697102..dd7fde04 100644 --- a/webui/src/main/kotlin/com/simiacryptus/diff/IterativePatchUtil.kt +++ b/webui/src/main/kotlin/com/simiacryptus/diff/IterativePatchUtil.kt @@ -55,7 +55,7 @@ object IterativePatchUtil { // Step 3: Establish a distance metric for matches based on Levenshtein distance and distance to established links. // Use this to establish the links based on a shortest-first policy and iterate until no more good matches are found. - linkByLevenshteinDistance(sourceLines, patchLines) + //linkByLevenshteinDistance(sourceLines, patchLines) // Generate the patched text using the established links return generatePatchedTextUsingLinks(sourceLines, patchLines) @@ -71,6 +71,11 @@ object IterativePatchUtil { val patchedTextBuilder = StringBuilder() val sourceLineBuffer = sourceLines.toMutableList() + // Add any leading lines from the source that are not in the patch + while (sourceLineBuffer.firstOrNull()?.matchingLine == null) { + patchedTextBuilder.appendLine(sourceLineBuffer.removeFirst().line) + } + // Add any leading 'add' lines from the patch val patchLines = patchLines.toMutableList() while (patchLines.firstOrNull()?.type == LineType.ADD) { @@ -108,6 +113,7 @@ object IterativePatchUtil { return patchedTextBuilder.toString().trimEnd() } + // ... rest of the file remains unchanged /** * Links lines between the source and the patch that are unique and match exactly. * @param sourceLines The source lines. diff --git a/webui/src/test/kotlin/com/simiacryptus/diff/IterativePatchUtilTest.kt b/webui/src/test/kotlin/com/simiacryptus/diff/IterativePatchUtilTest.kt index 9bd1fe73..ecfd484a 100644 --- a/webui/src/test/kotlin/com/simiacryptus/diff/IterativePatchUtilTest.kt +++ b/webui/src/test/kotlin/com/simiacryptus/diff/IterativePatchUtilTest.kt @@ -1,6 +1,5 @@ package com.simiacryptus.diff -import org.intellij.lang.annotations.Language import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test @@ -154,796 +153,5 @@ class IterativePatchUtilTest { ) } -/* - - @Test - fun testFromData2() { - @Language("KT") val source = """ -type RGB = { - r: number; - g: number; - b: number; -}; - -export class ColorMixer { - // ... other methods ... - - public static hexToRgb(hex: string): RGB { - // ... existing implementation ... - } - - public static convertHexToRgb(hex: string): RGB { - return this.hexToRgb(hex); - } - - private static hexToRgb(hex: string): RGB { - // ... other methods ... - public - mixColors(...colors - : - string[] - ): - string - { - // Implementation of color mixing logic - // This is a placeholder implementation - return colors[0]; // Return the first color for now - } - - // ... existing methods ... - } - - private static clamp(value: number): number { - return Math.max(0, Math.min(255, Math.round(value))); - } - - private static rgbToHex(rgb: RGB): string { - return `#${'$'}{ColorMixer.clamp(rgb.r).toString(16).padStart(2, '0')}${'$'}{ColorMixer.clamp(rgb.g).toString(16).padStart(2, '0')}${'$'}{ColorMixer.clamp(rgb.b).toString(16).padStart(2, '0')}`; - } - - // ... other methods ... -} - -// ... other methods ... -} -const result = "/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})${'$'}/i".exec(hex); -return result ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16) -} : {r: 0, g: 0, b: 0}; -} - -static -mixAdditive(...colors -: -string[] -): -string -{ - if (colors.length === 0) return '#000000'; - - const mixed: RGB = colors.reduce((acc, color) => { - const rgb = ColorMixer.hexToRgb(color); - return { - r: acc.r + rgb.r, - g: acc.g + rgb.g, - b: acc.b + rgb.b - }; - }, {r: 0, g: 0, b: 0}); - - const count = colors.length; - mixed.r = ColorMixer.clamp(mixed.r / count); - mixed.g = ColorMixer.clamp(mixed.g / count); - mixed.b = ColorMixer.clamp(mixed.b / count); - - return ColorMixer.rgbToHex(mixed); -} - -static -mixSubtractive(...colors -: -string[] -): -string -{ - if (colors.length === 0) return '#FFFFFF'; - - const mixed: RGB = colors.reduce((acc, color) => { - const rgb = ColorMixer.hexToRgb(color); - return { - r: acc.r * (rgb.r / 255), - g: acc.g * (rgb.g / 255), - b: acc.b * (rgb.b / 255) - }; - }, {r: 255, g: 255, b: 255}); - - mixed.r = ColorMixer.clamp(mixed.r); - mixed.g = ColorMixer.clamp(mixed.g); - mixed.b = ColorMixer.clamp(mixed.b); - - return ColorMixer.rgbToHex(mixed); -} - -static -getComplementaryColor(color -: -string -): -string -{ - const rgb = ColorMixer.hexToRgb(color); - const complementary: RGB = { - r: 255 - rgb.r, - g: 255 - rgb.g, - b: 255 - rgb.b - }; - return ColorMixer.rgbToHex(complementary); -} - -static -getLightness(color -: -string -): -number -{ - const rgb = ColorMixer.hexToRgb(color); - return (Math.max(rgb.r, rgb.g, rgb.b) + Math.min(rgb.r, rgb.g, rgb.b)) / (2 * 255); -} - -static -adjustLightness(color -: -string, amount -: -number -): -string -{ - const rgb = ColorMixer.hexToRgb(color); - const hsl = ColorMixer.rgbToHsl(rgb); - hsl.l = Math.max(0, Math.min(1, hsl.l + amount)); - return ColorMixer.rgbToHex(ColorMixer.hslToRgb(hsl)); -} - -private static -rgbToHsl(rgb -: -RGB -): -{ - number, s -: - number, l -: - number -} -{ - const r = rgb.r / 255; - const g = rgb.g / 255; - const b = rgb.b / 255; - const max = Math.max(r, g, b); - const min = Math.min(r, g, b); - let h: number; - const l = (max + min) / 2; - - if (max === min) { - h = 0; // Achromatic - } else { - h = s = 0; - } -else - { - const d = max - min; - const s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch (max) { - case r: - h = (g - b) / d + (g < b ? 6 : 0); - break; - case g: - h = (b - r) / d + 2; - break; - case b: - h = (r - g) / d + 4; - break; - default: - h = 0; // This should never happen, but it satisfies the type checker - case r: - h = (g - b) / d + (g < b ? 6 : 0); - break; - case g: - h = (b - r) / d + 2; - break; - case b: - h = (r - g) / d + 4; - break; - } - h = h / 6; - } - - return {h, s, l}; -} - -private static -hslToRgb(hsl -: -{ - number, s -: - number, l -: - number -} -): -RGB -{ - const {h, s, l} = hsl; - let r, g, b; - - if (s === 0) { - r = g = b = l; - } else { - const hue2rgb = (p: number, q: number, t: number) => { - if (t < 0) t += 1; - if (t > 1) t -= 1; - if (t < 1 / 6) return p + (q - p) * 6 * t; - if (t < 1 / 2) return q; - if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; - return p; - }; - - const q = l < 0.5 ? l * (1 + s) : l + s - l * s; - const p = 2 * l - q; - r = hue2rgb(p, q, h + 1 / 3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1 / 3); - } - - return { - r: Math.round(r * 255), - g: Math.round(g * 255), - b: Math.round(b * 255) - }; -} -} - """.trimIndent() - val patch = """ - | export class ColorMixer { - |+ public mixColors(...colors: string[]): string { - |+ if (colors.length === 0) return '#000000'; - |+ if (colors.length === 1) return colors[0]; - |+ - |+ const rgbColors = colors.map(color => this.hexToRgb(color)); - |+ const mixedRgb = rgbColors.reduce((acc, rgb) => ({ - |+ r: acc.r + rgb.r, - |+ g: acc.g + rgb.g, - |+ b: acc.b + rgb.b - |+ })); - |+ - |+ const avgRgb = { - |+ r: Math.round(mixedRgb.r / colors.length), - |+ g: Math.round(mixedRgb.g / colors.length), - |+ b: Math.round(mixedRgb.b / colors.length) - |+ }; - |+ - |+ return this.rgbToHex(avgRgb); - |+ } - | - | public static hexToRgb(hex: string): RGB { - | // Existing implementation... - | } - | - | private static rgbToHex(rgb: RGB): string { - | // Existing implementation... - | } - | - | // Other existing methods... - | } - """.trimMargin() - val expected = """ -type RGB = { - r: number; - g: number; - b: number; -}; - -export class ColorMixer { - public mixColors(...colors: string[]): string { - if (colors.length === 0) return '#000000'; - if (colors.length === 1) return colors[0]; - - const rgbColors = colors.map(color => this.hexToRgb(color)); - const mixedRgb = rgbColors.reduce((acc, rgb) => ({ - r: acc.r + rgb.r, - g: acc.g + rgb.g, - b: acc.b + rgb.b - })); - const avgRgb = { - r: Math.round(mixedRgb.r / colors.length), - g: Math.round(mixedRgb.g / colors.length), - b: Math.round(mixedRgb.b / colors.length) - }; - return this.rgbToHex(avgRgb); - } - // ... other methods ... - - public static hexToRgb(hex: string): RGB { - // ... existing implementation ... - } - - public static convertHexToRgb(hex: string): RGB { - return this.hexToRgb(hex); - } - - private static hexToRgb(hex: string): RGB { - // ... other methods ... - public - mixColors(...colors - : - string[] - ): - string - { - // Implementation of color mixing logic - // This is a placeholder implementation - return colors[0]; // Return the first color for now - } - - // ... existing methods ... - } - - private static clamp(value: number): number { - return Math.max(0, Math.min(255, Math.round(value))); - } - - private static rgbToHex(rgb: RGB): string { - return `#${'$'}{ColorMixer.clamp(rgb.r).toString(16).padStart(2, '0')}${'$'}{ColorMixer.clamp(rgb.g).toString(16).padStart(2, '0')}${'$'}{ColorMixer.clamp(rgb.b).toString(16).padStart(2, '0')}`; - } - - // ... other methods ... -} - -// ... other methods ... -} -const result = "/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})${'$'}/i".exec(hex); -return result ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16) -} : {r: 0, g: 0, b: 0}; -} - -static -mixAdditive(...colors -: -string[] -): -string -{ - if (colors.length === 0) return '#000000'; - - const mixed: RGB = colors.reduce((acc, color) => { - const rgb = ColorMixer.hexToRgb(color); - return { - r: acc.r + rgb.r, - g: acc.g + rgb.g, - b: acc.b + rgb.b - }; - }, {r: 0, g: 0, b: 0}); - - const count = colors.length; - mixed.r = ColorMixer.clamp(mixed.r / count); - mixed.g = ColorMixer.clamp(mixed.g / count); - mixed.b = ColorMixer.clamp(mixed.b / count); - - return ColorMixer.rgbToHex(mixed); -} - -static -mixSubtractive(...colors -: -string[] -): -string -{ - if (colors.length === 0) return '#FFFFFF'; - - const mixed: RGB = colors.reduce((acc, color) => { - const rgb = ColorMixer.hexToRgb(color); - return { - r: acc.r * (rgb.r / 255), - g: acc.g * (rgb.g / 255), - b: acc.b * (rgb.b / 255) - }; - }, {r: 255, g: 255, b: 255}); - - mixed.r = ColorMixer.clamp(mixed.r); - mixed.g = ColorMixer.clamp(mixed.g); - mixed.b = ColorMixer.clamp(mixed.b); - - return ColorMixer.rgbToHex(mixed); -} - -static -getComplementaryColor(color -: -string -): -string -{ - const rgb = ColorMixer.hexToRgb(color); - const complementary: RGB = { - r: 255 - rgb.r, - g: 255 - rgb.g, - b: 255 - rgb.b - }; - return ColorMixer.rgbToHex(complementary); -} - -static -getLightness(color -: -string -): -number -{ - const rgb = ColorMixer.hexToRgb(color); - return (Math.max(rgb.r, rgb.g, rgb.b) + Math.min(rgb.r, rgb.g, rgb.b)) / (2 * 255); -} - -static -adjustLightness(color -: -string, amount -: -number -): -string -{ - const rgb = ColorMixer.hexToRgb(color); - const hsl = ColorMixer.rgbToHsl(rgb); - hsl.l = Math.max(0, Math.min(1, hsl.l + amount)); - return ColorMixer.rgbToHex(ColorMixer.hslToRgb(hsl)); -} - -private static -rgbToHsl(rgb -: -RGB -): -{ - number, s -: - number, l -: - number -} -{ - const r = rgb.r / 255; - const g = rgb.g / 255; - const b = rgb.b / 255; - const max = Math.max(r, g, b); - const min = Math.min(r, g, b); - let h: number; - const l = (max + min) / 2; - - if (max === min) { - h = 0; // Achromatic - } else { - h = s = 0; - } -else - { - const d = max - min; - const s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch (max) { - case r: - h = (g - b) / d + (g < b ? 6 : 0); - break; - case g: - h = (b - r) / d + 2; - break; - case b: - h = (r - g) / d + 4; - break; - default: - h = 0; // This should never happen, but it satisfies the type checker - case r: - h = (g - b) / d + (g < b ? 6 : 0); - break; - case g: - h = (b - r) / d + 2; - break; - case b: - h = (r - g) / d + 4; - break; - } - h = h / 6; - } - - return {h, s, l}; -} - -private static -hslToRgb(hsl -: -{ - number, s -: - number, l -: - number -} -): -RGB -{ - const {h, s, l} = hsl; - let r, g, b; - - if (s === 0) { - r = g = b = l; - } else { - const hue2rgb = (p: number, q: number, t: number) => { - if (t < 0) t += 1; - if (t > 1) t -= 1; - if (t < 1 / 6) return p + (q - p) * 6 * t; - if (t < 1 / 2) return q; - if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; - return p; - }; - - const q = l < 0.5 ? l * (1 + s) : l + s - l * s; - const p = 2 * l - q; - r = hue2rgb(p, q, h + 1 / 3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1 / 3); - } - - return { - r: Math.round(r * 255), - g: Math.round(g * 255), - b: Math.round(b * 255) - }; -} -} - """.trimIndent() - val result = IterativePatchUtil.patch(source, patch) - Assertions.assertEquals( - expected.replace("\r\n", "\n"),//.replace("\\s{2,}".toRegex(), " "), - result.replace("\r\n", "\n")//.replace("\\s{2,}".toRegex(), " ") - ) - } - - @Test - fun testFromData3() { - val source = """ -import {Scene} from './Scene'; - -export class Game { - private currentScene: Scene | null = null; - private isRunning: boolean = false; - private lastTimestamp: number = 0; - - constructor(private canvas: HTMLCanvasElement) { - } - - public start(): void { - this.isRunning = true; - this.lastTimestamp = performance.now(); - requestAnimationFrame(this.gameLoop.bind(this)); - } - - public stop(): void { - this.isRunning = false; - } - - public setScene(scene: Scene): void { - this.currentScene = scene; - } - - private gameLoop(timestamp: number): void { - if (!this.isRunning) return; - - const deltaTime = (timestamp - this.lastTimestamp) / 1000; // Convert to seconds - this.lastTimestamp = timestamp; - - this.update(deltaTime); - this.render(); - - requestAnimationFrame(this.gameLoop.bind(this)); - } - - private update(deltaTime: number): void { - if (this.currentScene) { - this.currentScene.update(deltaTime); - } - } - - private render(): void { - const ctx = this.canvas.getContext('2d'); - if (!ctx) return; - - // Clear the canvas - ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); - - if (this.currentScene) { - this.currentScene.render(ctx); - } - } -} - """.trimIndent() - val patch = """ - constructor(private canvas: HTMLCanvasElement) { -+ this.width = canvas.width; -+ this.height = canvas.height; - } - -+ public width: number; -+ public height: number; - """.trimIndent() - val expected = """ -import {Scene} from './Scene'; - -export class Game { - private currentScene: Scene | null = null; - private isRunning: boolean = false; - private lastTimestamp: number = 0; - - constructor(private canvas: HTMLCanvasElement) { - this.width = canvas.width; - this.height = canvas.height; - } - - public width: number; - public height: number; - - public start(): void { - this.isRunning = true; - this.lastTimestamp = performance.now(); - requestAnimationFrame(this.gameLoop.bind(this)); - } - - public stop(): void { - this.isRunning = false; - } - - public setScene(scene: Scene): void { - this.currentScene = scene; - } - - private gameLoop(timestamp: number): void { - if (!this.isRunning) return; - - const deltaTime = (timestamp - this.lastTimestamp) / 1000; // Convert to seconds - this.lastTimestamp = timestamp; - - this.update(deltaTime); - this.render(); - - requestAnimationFrame(this.gameLoop.bind(this)); - } - - private update(deltaTime: number): void { - if (this.currentScene) { - this.currentScene.update(deltaTime); - } - } - - private render(): void { - const ctx = this.canvas.getContext('2d'); - if (!ctx) return; - - // Clear the canvas - ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); - - if (this.currentScene) { - this.currentScene.render(ctx); - } - } -} - """.trimIndent() - val result = IterativePatchUtil.patch(source, patch) - Assertions.assertEquals( - expected.replace("\r\n", "\n"),//.replace("\\s{2,}".toRegex(), " "), - result.replace("\r\n", "\n")//.replace("\\s{2,}".toRegex(), " ") - ) - } - - @Test - fun testFromData4() { - val source = """ -import {ColorMixer} from '@/systems/ColorMixer'; - -describe('ColorMixer', () => { - const colorMixer = new ColorMixer(); - - test('mixing red and green should result in yellow', () => { - let colorMixer: ColorMixer; - - beforeEach(() => { - colorMixer = new ColorMixer(); - }); - - test('mixing red and green should produce yellow', () => { - const result = colorMixer.mixColors('red', 'green'); - expect(result).toBe('red'); // Temporary expectation based on placeholder implementation - }); - - test('mixing blue and yellow should result in green', () => { - const result = colorMixer.mixColors('blue', 'yellow'); - expect(result).toBe('blue'); // Temporary expectation based on placeholder implementation - }); - - test('mixing red, green, and blue should result in white', () => { - const result = colorMixer.mixColors('red', 'green', 'blue'); - expect(result).toBe('red'); // Temporary expectation based on placeholder implementation - }); - }); - """.trimIndent() - val patch = """ - import {ColorMixer} from '@/systems/ColorMixer'; - - describe('ColorMixer', () => { -- const colorMixer = new ColorMixer(); -+ let colorMixer: ColorMixer; - - beforeEach(() => { - colorMixer = new ColorMixer(); - }); - - test('mixing red and green should produce yellow', () => { - const result = colorMixer.mixColors('red', 'green'); -- expect(result).toBe('red'); // Temporary expectation based on placeholder implementation -+ expect(result).toBe('#ffff00'); // Yellow in hex - }); - - test('mixing blue and yellow should result in green', () => { - const result = colorMixer.mixColors('blue', 'yellow'); -- expect(result).toBe('blue'); // Temporary expectation based on placeholder implementation -+ expect(result).toBe('#80ff80'); // Light green in hex - }); - - test('mixing red, green, and blue should result in white', () => { - const result = colorMixer.mixColors('red', 'green', 'blue'); -- expect(result).toBe('red'); // Temporary expectation based on placeholder implementation -+ expect(result).toBe('#ffffff'); // White in hex - }); - }); - """.trimIndent() - val result = IterativePatchUtil.patch(source, patch) - val expected = """ -import {ColorMixer} from '@/systems/ColorMixer'; - -describe('ColorMixer', () => { - const colorMixer = new ColorMixer(); - let colorMixer: ColorMixer; - - beforeEach(() => { - colorMixer = new ColorMixer(); - }); - - test('mixing red and green should produce yellow', () => { - const result = colorMixer.mixColors('red', 'green'); - expect(result).toBe('#ffff00'); // Yellow in hex - }); - - test('mixing blue and yellow should result in green', () => { - const result = colorMixer.mixColors('blue', 'yellow'); - expect(result).toBe('#80ff80'); // Light green in hex - }); - - test('mixing red, green, and blue should result in white', () => { - const result = colorMixer.mixColors('red', 'green', 'blue'); - expect(result).toBe('#ffffff'); // White in hex - }); -}); - """.trimIndent() - Assertions.assertEquals( - expected.replace("\r\n", "\n"),//.replace("\\s{2,}".toRegex(), " "), - result.replace("\r\n", "\n")//.replace("\\s{2,}".toRegex(), " ") - ) - } -*/ } \ No newline at end of file