diff --git a/pkgs/jnigen/pubspec.yaml b/pkgs/jnigen/pubspec.yaml index 5563aa6506..f8fc720b61 100644 --- a/pkgs/jnigen/pubspec.yaml +++ b/pkgs/jnigen/pubspec.yaml @@ -33,6 +33,7 @@ dependencies: dev_dependencies: build_runner: ^2.4.12 + crypto: ^3.0.6 dart_flutter_team_lints: ^3.2.0 jni: ^0.13.0 json_serializable: ^6.8.0 diff --git a/pkgs/jnigen/test/kotlin_test/kotlin/src/main/kotlin/com/github/dart_lang/jnigen/Operators.kt b/pkgs/jnigen/test/kotlin_test/kotlin/src/main/kotlin/com/github/dart_lang/jnigen/Operators.kt index f0df56e8a3..f0a19b31e5 100644 --- a/pkgs/jnigen/test/kotlin_test/kotlin/src/main/kotlin/com/github/dart_lang/jnigen/Operators.kt +++ b/pkgs/jnigen/test/kotlin_test/kotlin/src/main/kotlin/com/github/dart_lang/jnigen/Operators.kt @@ -1,6 +1,6 @@ package com.github.dart_lang.jnigen -class Operators(var value: Int) { +public class Operators(var value: Int) { operator fun plus(op: Operators): Operators { return Operators(value + op.value) } diff --git a/pkgs/jnigen/test/test_util/bindings_test_setup.dart b/pkgs/jnigen/test/test_util/bindings_test_setup.dart index 508fc66acc..52caa535d2 100644 --- a/pkgs/jnigen/test/test_util/bindings_test_setup.dart +++ b/pkgs/jnigen/test/test_util/bindings_test_setup.dart @@ -9,8 +9,12 @@ // reuse of the old JVM with old classpath if we have separate tests with // different classpaths. +// ignore_for_file: curly_braces_in_flow_control_structures, lines_longer_than_80_chars, prefer_const_declarations, omit_local_variable_types + +import 'dart:convert'; import 'dart:io'; +import 'package:crypto/crypto.dart'; import 'package:jni/jni.dart'; import 'package:path/path.dart' hide equals; @@ -42,7 +46,7 @@ Future bindingsTestSetup() async { ]); final jacksonJars = await getJarPaths(join(jacksonCoreTest, 'third_party')); - + print('running mvn package:'); await runCommand( 'mvn', ['package'], @@ -53,6 +57,148 @@ Future bindingsTestSetup() async { final kotlinTestJar = join(kotlinTestKotlin, 'target', 'kotlin_test-jar-with-dependencies.jar'); + // --- Configuration --- + final jarFilePath = kotlinTestJar; + // Path to the class file *inside* the JAR + final classPathInJar = 'com/github/dart_lang/jnigen/Operators.class'; + // Temporary file for extracting the class + final tempFilePath = 'Operators.class.tmp'; + // --- End Configuration --- + + print('--- Starting JAR Debug ---'); + print('Timestamp: ${DateTime.now()}'); + print('JAR File Path: $jarFilePath'); + print('Class Path in JAR: $classPathInJar'); + print(''); + + final jarFile = File(jarFilePath); + + // 1. Check JAR File Existence + print('1. Checking JAR file existence...'); + final jarExists = await jarFile.exists(); + print(' Exists: $jarExists'); + if (!jarExists) { + print(' ERROR: JAR file not found at specified path. Aborting.'); + print('--- End JAR Debug ---'); + exit(1); // Exit with error + } + print(''); + + // 2. Check if Operators.class is listed in JAR contents + print('2. Checking if class is listed in JAR contents (using `jar tf`)...'); + bool classListed = false; + try { + // Ensure 'jar' command is available in PATH + final listResult = + await Process.run('jar', ['tf', jarFilePath], runInShell: true); + + if (listResult.exitCode == 0) { + final output = utf8.decode(listResult.stdout as List); + if (output.contains(classPathInJar)) { + classListed = true; + print(' Class "$classPathInJar" IS listed in JAR contents.'); + } else { + print( + ' WARNING: Class "$classPathInJar" is NOT listed in JAR contents!'); + print( + ' Full `jar tf` output:\n${output.substring(0, output.length > 1000 ? 1000 : output.length)}...'); // Print first 1000 chars + } + } else { + print( + ' ERROR: `jar tf` command failed with exit code ${listResult.exitCode}.'); + print(' Stderr: ${utf8.decode(listResult.stderr as List)}'); + } + } catch (e) { + print( + ' ERROR: Failed to run `jar tf`. Is `jar` (from JDK) in your PATH? Exception: $e'); + } + print(''); + + // 3. Extract Operators.class and get its info + print('3. Attempting to extract class file using `unzip -p`...'); + final tempFile = File(tempFilePath); + bool extractionAttempted = false; + bool extractionSucceeded = false; + int extractedSize = -1; + String extractedSha256 = 'N/A'; + + // Clean up potentially leftover temp file + if (await tempFile.exists()) { + await tempFile.delete(); + } + + try { + // Ensure 'unzip' command is available in PATH + // Use Process.start to pipe output to file, as `unzip -p` writes to stdout + extractionAttempted = true; + final process = await Process.start( + 'unzip', + ['-p', jarFilePath, classPathInJar], + runInShell: true, // May be needed depending on PATH setup + ); + + // Pipe stdout to the temporary file + final fileSink = tempFile.openWrite(); + await process.stdout.pipe(fileSink); + + // Wait for the process to exit and check code + final exitCode = await process.exitCode; + + if (exitCode == 0) { + // Check if file was actually created and has content + if (await tempFile.exists() && await tempFile.length() > 0) { + extractionSucceeded = true; + print( + ' Extraction via `unzip -p` seems successful (exit code 0, file created).'); + + // 4. Get Size + final fileStat = await tempFile.stat(); + extractedSize = fileStat.size; + print(' Extracted Size: $extractedSize bytes'); + + // 5. Calculate Checksum + final bytes = await tempFile.readAsBytes(); + final digest = sha256.convert(bytes); + extractedSha256 = digest.toString(); + print(' Extracted SHA256: $extractedSha256'); + } else { + print( + ' WARNING: `unzip -p` exited with 0, but temp file "$tempFilePath" is missing or empty.'); + if (await tempFile.exists()) + await tempFile.delete(); // Clean up empty file + } + } else { + print(' ERROR: `unzip -p` command failed with exit code $exitCode.'); + // Try to read stderr (might not capture much depending on how unzip fails) + // Note: Reading stderr after piping stdout might be tricky / lose data. + // Consider alternative extraction methods if this fails often. + } + } catch (e) { + print( + ' ERROR: Failed to run `unzip -p`. Is `unzip` in your PATH? Exception: $e'); + } finally { + // 6. Clean up temp file + if (await tempFile.exists()) { + try { + await tempFile.delete(); + print(' Temporary file "$tempFilePath" deleted.'); + } catch (e) { + print( + ' WARNING: Failed to delete temporary file "$tempFilePath". Exception: $e'); + } + } + } + print(''); + + print('--- Summary ---'); + print('JAR Exists: $jarExists'); + print('Class Listed in JAR: $classListed'); + print('Extraction Attempted: $extractionAttempted'); + print('Extraction Succeeded: $extractionSucceeded'); + print('Extracted Size: $extractedSize bytes'); + print('Extracted SHA256: $extractedSha256'); + print('--- End JAR Debug ---'); + if (!Platform.isAndroid) { Jni.spawn(dylibDir: join('build', 'jni_libs'), classPath: [ jniJar,