From ae7a883b3d3c3fee028dc944300ecd94d2969f7b Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Tue, 4 Feb 2025 06:56:46 +0100 Subject: [PATCH 01/43] Update airframe-json, airspec to 2025.1.1 (#872) --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 31280a69..82ec44f0 100644 --- a/build.sbt +++ b/build.sbt @@ -5,7 +5,7 @@ Global / concurrentRestrictions := Seq( Tags.limit(Tags.Test, 1) ) -val AIRFRAME_VERSION = "24.12.2" +val AIRFRAME_VERSION = "2025.1.1" // Use dynamic snapshot version strings for non tagged versions ThisBuild / dynverSonatypeSnapshots := true From 91bc7f2029c4bb6e8c489fecf8c1525f0111012e Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Tue, 4 Feb 2025 06:56:56 +0100 Subject: [PATCH 02/43] Update scala-collection-compat to 2.13.0 (#871) --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 82ec44f0..235f6286 100644 --- a/build.sbt +++ b/build.sbt @@ -92,7 +92,7 @@ lazy val msgpackCore = Project(id = "msgpack-core", base = file("msgpack-core")) "org.msgpack" % "msgpack" % "0.6.12" % "test", // For integration test with Akka "com.typesafe.akka" %% "akka-actor" % "2.6.20" % "test", - "org.scala-lang.modules" %% "scala-collection-compat" % "2.12.0" % "test" + "org.scala-lang.modules" %% "scala-collection-compat" % "2.13.0" % "test" ) ) From f480b7bf828f08961f85a671758bd7f383136956 Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Tue, 4 Feb 2025 06:57:07 +0100 Subject: [PATCH 03/43] Update sbt-scalafmt to 2.5.4 (#869) --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index e702479f..01d5e0ad 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -5,7 +5,7 @@ addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.1") //addSbtPlugin("com.github.sbt" % "sbt-jacoco" % "3.3.0") addSbtPlugin("org.xerial.sbt" % "sbt-jcheckstyle" % "0.2.1") addSbtPlugin("com.github.sbt" % "sbt-osgi" % "0.10.0") -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.2") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.4") addSbtPlugin("com.github.sbt" % "sbt-dynver" % "5.1.0") scalacOptions ++= Seq("-deprecation", "-feature") From 1cbd05f7ad1a44d8d78f6a6d55f0ce0fe78f386c Mon Sep 17 00:00:00 2001 From: brenbar <12563144+brenbar@users.noreply.github.com> Date: Mon, 10 Feb 2025 19:55:08 -0600 Subject: [PATCH 04/43] Add support for jackson field ids (#868) * Add test demonstrating field id case * Fix java 8 error * Add missing import * Add missing throws * Cleanup unused imports * Cleanup test * Implement jackson field ids * Address feedback from @komamitsu * Address feedback from @komamitsu * Address feedback from @komamitsu --- .../dataformat/MessagePackFactory.java | 9 +- .../dataformat/MessagePackGenerator.java | 22 ++- .../jackson/dataformat/MessagePackParser.java | 5 + .../MessagePackDataformatForFieldIdTest.java | 132 ++++++++++++++++++ 4 files changed, 164 insertions(+), 4 deletions(-) create mode 100644 msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatForFieldIdTest.java diff --git a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackFactory.java b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackFactory.java index bb5064f1..dbd2a465 100644 --- a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackFactory.java +++ b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackFactory.java @@ -39,6 +39,7 @@ public class MessagePackFactory private final MessagePack.PackerConfig packerConfig; private boolean reuseResourceInGenerator = true; private boolean reuseResourceInParser = true; + private boolean supportIntegerKeys = false; private ExtensionTypeCustomDeserializers extTypeCustomDesers; public MessagePackFactory() @@ -74,6 +75,12 @@ public MessagePackFactory setReuseResourceInParser(boolean reuseResourceInParser return this; } + public MessagePackFactory setSupportIntegerKeys(boolean supportIntegerKeys) + { + this.supportIntegerKeys = supportIntegerKeys; + return this; + } + public MessagePackFactory setExtTypeCustomDesers(ExtensionTypeCustomDeserializers extTypeCustomDesers) { this.extTypeCustomDesers = extTypeCustomDesers; @@ -84,7 +91,7 @@ public MessagePackFactory setExtTypeCustomDesers(ExtensionTypeCustomDeserializer public JsonGenerator createGenerator(OutputStream out, JsonEncoding enc) throws IOException { - return new MessagePackGenerator(_generatorFeatures, _objectCodec, out, packerConfig, reuseResourceInGenerator); + return new MessagePackGenerator(_generatorFeatures, _objectCodec, out, packerConfig, reuseResourceInGenerator, supportIntegerKeys); } @Override diff --git a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackGenerator.java b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackGenerator.java index 11aba6e5..abb5089e 100644 --- a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackGenerator.java +++ b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackGenerator.java @@ -50,6 +50,7 @@ public class MessagePackGenerator private static final ThreadLocal messageBufferOutputHolder = new ThreadLocal<>(); private final OutputStream output; private final MessagePack.PackerConfig packerConfig; + private final boolean supportIntegerKeys; private int currentParentElementIndex = -1; private int currentState = IN_ROOT; @@ -188,13 +189,15 @@ private MessagePackGenerator( int features, ObjectCodec codec, OutputStream out, - MessagePack.PackerConfig packerConfig) + MessagePack.PackerConfig packerConfig, + boolean supportIntegerKeys) { super(features, codec); this.output = out; this.messagePacker = packerConfig.newPacker(out); this.packerConfig = packerConfig; this.nodes = new ArrayList<>(); + this.supportIntegerKeys = supportIntegerKeys; } public MessagePackGenerator( @@ -202,7 +205,8 @@ public MessagePackGenerator( ObjectCodec codec, OutputStream out, MessagePack.PackerConfig packerConfig, - boolean reuseResourceInGenerator) + boolean reuseResourceInGenerator, + boolean supportIntegerKeys) throws IOException { super(features, codec); @@ -210,6 +214,7 @@ public MessagePackGenerator( this.messagePacker = packerConfig.newPacker(getMessageBufferOutputForOutputStream(out, reuseResourceInGenerator)); this.packerConfig = packerConfig; this.nodes = new ArrayList<>(); + this.supportIntegerKeys = supportIntegerKeys; } private MessageBufferOutput getMessageBufferOutputForOutputStream( @@ -373,7 +378,7 @@ else if (v instanceof MessagePackExtensionType) { else { messagePacker.flush(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - MessagePackGenerator messagePackGenerator = new MessagePackGenerator(getFeatureMask(), getCodec(), outputStream, packerConfig); + MessagePackGenerator messagePackGenerator = new MessagePackGenerator(getFeatureMask(), getCodec(), outputStream, packerConfig, supportIntegerKeys); getCodec().writeValue(messagePackGenerator, v); output.write(outputStream.toByteArray()); } @@ -513,6 +518,17 @@ private void writeByteArrayTextKey(byte[] text, int offset, int len) throws IOEx addValueNode(new String(text, offset, len, DEFAULT_CHARSET)); } + @Override + public void writeFieldId(long id) throws IOException + { + if (this.supportIntegerKeys) { + addKeyNode(id); + } + else { + super.writeFieldId(id); + } + } + @Override public void writeFieldName(String name) { diff --git a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackParser.java b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackParser.java index 4876c797..e59b7f57 100644 --- a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackParser.java +++ b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackParser.java @@ -621,6 +621,11 @@ public String currentName() return streamReadContext.getCurrentName(); } + public boolean isCurrentFieldId() + { + return this.type == Type.INT || this.type == Type.LONG; + } + @Override public String getCurrentName() throws IOException diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatForFieldIdTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatForFieldIdTest.java new file mode 100644 index 00000000..0e102ba8 --- /dev/null +++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatForFieldIdTest.java @@ -0,0 +1,132 @@ +// +// MessagePack for Java +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +package org.msgpack.jackson.dataformat; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.KeyDeserializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.deser.NullValueProvider; +import com.fasterxml.jackson.databind.deser.impl.JDKValueInstantiators; +import com.fasterxml.jackson.databind.deser.std.MapDeserializer; +import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.type.TypeFactory; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.LinkedHashMap; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class MessagePackDataformatForFieldIdTest +{ + static class MessagePackMapDeserializer extends MapDeserializer + { + public static KeyDeserializer keyDeserializer = new KeyDeserializer() + { + @Override + public Object deserializeKey(String s, DeserializationContext deserializationContext) + throws IOException + { + JsonParser parser = deserializationContext.getParser(); + if (parser instanceof MessagePackParser) { + MessagePackParser p = (MessagePackParser) parser; + if (p.isCurrentFieldId()) { + return Integer.valueOf(s); + } + } + return s; + } + }; + + public MessagePackMapDeserializer() + { + super( + TypeFactory.defaultInstance().constructMapType(Map.class, Object.class, Object.class), + JDKValueInstantiators.findStdValueInstantiator(null, LinkedHashMap.class), + keyDeserializer, null, null); + } + + public MessagePackMapDeserializer(MapDeserializer src, KeyDeserializer keyDeser, + JsonDeserializer valueDeser, TypeDeserializer valueTypeDeser, NullValueProvider nuller, + Set ignorable, Set includable) + { + super(src, keyDeser, valueDeser, valueTypeDeser, nuller, ignorable, includable); + } + + @Override + protected MapDeserializer withResolved(KeyDeserializer keyDeser, TypeDeserializer valueTypeDeser, + JsonDeserializer valueDeser, NullValueProvider nuller, Set ignorable, + Set includable) + { + return new MessagePackMapDeserializer(this, keyDeser, (JsonDeserializer) valueDeser, valueTypeDeser, + nuller, ignorable, includable); + } + } + + @Test + public void testMixedKeys() + throws IOException + { + ObjectMapper mapper = new ObjectMapper( + new MessagePackFactory() + .setSupportIntegerKeys(true) + ) + .registerModule(new SimpleModule() + .addDeserializer(Map.class, new MessagePackMapDeserializer())); + + Map map = new HashMap<>(); + map.put(1, "one"); + map.put("2", "two"); + + byte[] bytes = mapper.writeValueAsBytes(map); + Map deserializedInit = mapper.readValue(bytes, new TypeReference>() {}); + + Map expected = new HashMap<>(map); + Map actual = new HashMap<>(deserializedInit); + + assertEquals(expected, actual); + } + + @Test + public void testMixedKeysBackwardsCompatiable() + throws IOException + { + ObjectMapper mapper = new ObjectMapper(new MessagePackFactory()) + .registerModule(new SimpleModule() + .addDeserializer(Map.class, new MessagePackMapDeserializer())); + + Map map = new HashMap<>(); + map.put(1, "one"); + map.put("2", "two"); + + byte[] bytes = mapper.writeValueAsBytes(map); + Map deserializedInit = mapper.readValue(bytes, new TypeReference>() {}); + + Map expected = new HashMap<>(); + expected.put("1", "one"); + expected.put("2", "two"); + Map actual = new HashMap<>(deserializedInit); + + assertEquals(expected, actual); + } +} From f73e394e48fa8e0556e8b9739ca1a5c6424db168 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 19 Jul 2025 08:49:31 -0700 Subject: [PATCH 05/43] Add CLAUDE.md for AI-assisted development (#894) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This file provides essential guidance for Claude Code when working with the msgpack-java codebase, including common development commands and high-level architecture overview. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude --- CLAUDE.md | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..e01643b5 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,93 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +MessagePack-Java is a binary serialization library that provides a fast and compact alternative to JSON. The project consists of two main modules: +- **msgpack-core**: Standalone MessagePack implementation with no external dependencies +- **msgpack-jackson**: Jackson integration for object mapping capabilities + +## Essential Development Commands + +### Build and Compile +```bash +./sbt compile # Compile source code +./sbt test:compile # Compile source and test code +./sbt package # Create JAR files +``` + +### Testing +```bash +./sbt test # Run all tests +./sbt ~test # Run tests continuously on file changes +./sbt testOnly *TestClass # Run specific test class +./sbt "testOnly *TestClass -- -z pattern" # Run tests matching pattern + +# Test with universal buffer mode (for compatibility testing) +./sbt test -J-Dmsgpack.universal-buffer=true +``` + +### Code Quality +```bash +./sbt jcheckStyle # Run checkstyle (Facebook Presto style) +./sbt scalafmtAll # Format Scala test code +``` + +### Publishing +```bash +./sbt publishLocal # Install to local .ivy2 repository +./sbt publishM2 # Install to local .m2 Maven repository +``` + +## Architecture Overview + +### Core API Structure +The main entry point is the `MessagePack` factory class which creates: +- **MessagePacker**: Serializes objects to MessagePack binary format +- **MessageUnpacker**: Deserializes MessagePack binary data + +Key locations: +- Core interfaces: `msgpack-core/src/main/java/org/msgpack/core/` +- Jackson integration: `msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/` + +### Buffer Management System +MessagePack uses an efficient buffer abstraction layer: +- **MessageBuffer**: Platform-optimized buffer implementations + - Uses `sun.misc.Unsafe` for performance when available + - Falls back to ByteBuffer on restricted platforms +- **MessageBufferInput/Output**: Manages buffer sequences for streaming + +### Jackson Integration +The msgpack-jackson module provides: +- **MessagePackFactory**: Jackson JsonFactory implementation +- **MessagePackMapper**: Pre-configured ObjectMapper for MessagePack +- Support for field IDs (integer keys) for compact serialization +- Extension type support including timestamps + +### Testing Structure +- **msgpack-core tests**: Written in Scala using AirSpec framework + - Location: `msgpack-core/src/test/scala/` +- **msgpack-jackson tests**: Written in Java using JUnit + - Location: `msgpack-jackson/src/test/java/` + +## Important JVM Options + +For JDK 17+ compatibility, these options are automatically added: +``` +--add-opens=java.base/java.nio=ALL-UNNAMED +--add-opens=java.base/sun.nio.ch=ALL-UNNAMED +``` + +## Code Style Requirements +- Java code follows Facebook Presto style (enforced by checkstyle) +- Scala test code uses Scalafmt with 180 character line limit +- Checkstyle runs automatically during compilation +- No external dependencies allowed in msgpack-core + +## Key Design Principles +1. **Zero Dependencies**: msgpack-core has no external dependencies +2. **Platform Optimization**: Uses platform-specific optimizations when available +3. **Streaming Support**: Both streaming and object-based APIs +4. **Type Safety**: Immutable Value hierarchy for type-safe data handling +5. **Extension Support**: Extensible type system for custom data types \ No newline at end of file From 032823bd60f2f5b859f4ae962f3cb96cbe2ae7a0 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 19 Jul 2025 09:18:02 -0700 Subject: [PATCH 06/43] Refactor CI to use matrix strategy and add JDK 24 support (#895) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace individual JDK test jobs with a single matrix-based job - Add JDK 24 to the test matrix (now tests JDK 8, 11, 17, 21, and 24) - Simplifies CI configuration and makes it easier to add new JDK versions 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude --- .github/workflows/CI.yml | 70 ++++++---------------------------------- 1 file changed, 10 insertions(+), 60 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 7ff24e9b..31f824e4 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -27,75 +27,25 @@ jobs: - uses: actions/checkout@v4 - name: jcheckstyle run: ./sbt jcheckStyle - test_jdk21: - name: Test JDK21 + + test: + name: Test JDK${{ matrix.java }} runs-on: ubuntu-latest + strategy: + matrix: + java: ['8', '11', '17', '21', '24'] steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: '21' + java-version: ${{ matrix.java }} - uses: actions/cache@v4 with: path: ~/.cache - key: ${{ runner.os }}-jdk21-${{ hashFiles('**/*.sbt') }} - restore-keys: ${{ runner.os }}-jdk21- + key: ${{ runner.os }}-jdk${{ matrix.java }}-${{ hashFiles('**/*.sbt') }} + restore-keys: ${{ runner.os }}-jdk${{ matrix.java }}- - name: Test run: ./sbt test - name: Universal Buffer Test - run: ./sbt test -J-Dmsgpack.universal-buffer=true - test_jdk17: - name: Test JDK17 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 - with: - distribution: 'zulu' - java-version: '17' - - uses: actions/cache@v4 - with: - path: ~/.cache - key: ${{ runner.os }}-jdk17-${{ hashFiles('**/*.sbt') }} - restore-keys: ${{ runner.os }}-jdk17- - - name: Test - run: ./sbt test - - name: Universal Buffer Test - run: ./sbt test -J-Dmsgpack.universal-buffer=true - test_jdk11: - name: Test JDK11 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 - with: - distribution: 'zulu' - java-version: '11' - - uses: actions/cache@v4 - with: - path: ~/.cache - key: ${{ runner.os }}-jdk11-${{ hashFiles('**/*.sbt') }} - restore-keys: ${{ runner.os }}-jdk11- - - name: Test - run: ./sbt test - - name: Universal Buffer Test - run: ./sbt test -J-Dmsgpack.universal-buffer=true - test_jdk8: - name: Test JDK8 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 - with: - distribution: 'zulu' - java-version: '8' - - uses: actions/cache@v4 - with: - path: ~/.cache - key: ${{ runner.os }}-jdk8-${{ hashFiles('**/*.sbt') }} - restore-keys: ${{ runner.os }}-jdk8- - - name: Test - run: ./sbt test - - name: Universal Buffer Test - run: ./sbt test -J-Dmsgpack.universal-buffer=true + run: ./sbt test -J-Dmsgpack.universal-buffer=true \ No newline at end of file From 18ab7b7eae2aee3d50205fce1926823930622541 Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Sat, 19 Jul 2025 18:21:43 +0200 Subject: [PATCH 07/43] Update sbt-scalafmt to 2.5.5 (#893) --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index 01d5e0ad..a15bdf51 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -5,7 +5,7 @@ addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.1") //addSbtPlugin("com.github.sbt" % "sbt-jacoco" % "3.3.0") addSbtPlugin("org.xerial.sbt" % "sbt-jcheckstyle" % "0.2.1") addSbtPlugin("com.github.sbt" % "sbt-osgi" % "0.10.0") -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.4") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.5") addSbtPlugin("com.github.sbt" % "sbt-dynver" % "5.1.0") scalacOptions ++= Seq("-deprecation", "-feature") From 8f1dddde88d5dcec0734224ddb447a0b893cc026 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 19 Jul 2025 09:33:44 -0700 Subject: [PATCH 08/43] Update sbt-dynver to 5.1.1 (#896) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #892 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index a15bdf51..d6844375 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -6,6 +6,6 @@ addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.1") addSbtPlugin("org.xerial.sbt" % "sbt-jcheckstyle" % "0.2.1") addSbtPlugin("com.github.sbt" % "sbt-osgi" % "0.10.0") addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.5") -addSbtPlugin("com.github.sbt" % "sbt-dynver" % "5.1.0") +addSbtPlugin("com.github.sbt" % "sbt-dynver" % "5.1.1") scalacOptions ++= Seq("-deprecation", "-feature") From 736765333c4043bea7a5e1157194b1f22e407a54 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 19 Jul 2025 09:39:43 -0700 Subject: [PATCH 09/43] Migrate from JUnit 4 to JUnit 5 to resolve deprecation warnings (#897) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update build.sbt to use JUnit 5 dependencies (jupiter + vintage) - Replace JUnit 4 imports with JUnit 5 equivalents - Convert @Test(expected=Exception.class) to assertThrows() - Update @Before to @BeforeEach annotation - Replace deprecated org.junit.Assert.assertThat with Hamcrest assertThat - Maintain backward compatibility with JUnit Vintage engine Fixes all JUnit deprecation warnings in msgpack-jackson tests. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude --- build.sbt | 9 +++++--- .../MessagePackDataformatForFieldIdTest.java | 4 ++-- .../MessagePackDataformatForPojoTest.java | 8 +++---- .../dataformat/MessagePackFactoryTest.java | 6 ++--- .../dataformat/MessagePackGeneratorTest.java | 23 +++++++++++-------- .../dataformat/MessagePackMapperTest.java | 6 ++--- .../dataformat/MessagePackParserTest.java | 17 ++++++++------ .../TimestampExtensionModuleTest.java | 8 +++---- ...gePackDataformatHugeDataBenchmarkTest.java | 2 +- ...essagePackDataformatPojoBenchmarkTest.java | 2 +- 10 files changed, 47 insertions(+), 38 deletions(-) diff --git a/build.sbt b/build.sbt index 235f6286..d4645a11 100644 --- a/build.sbt +++ b/build.sbt @@ -46,7 +46,8 @@ val buildSettings = Seq[Setting[_]]( Test / compile := ((Test / compile) dependsOn (Test / jcheckStyle)).value ) -val junitInterface = "com.github.sbt" % "junit-interface" % "0.13.3" % "test" +val junitJupiter = "org.junit.jupiter" % "junit-jupiter" % "5.11.4" % "test" +val junitVintage = "org.junit.vintage" % "junit-vintage-engine" % "5.11.4" % "test" // Project settings lazy val root = Project(id = "msgpack-java", base = file(".")) @@ -83,7 +84,8 @@ lazy val msgpackCore = Project(id = "msgpack-core", base = file("msgpack-core")) Test / fork := true, libraryDependencies ++= Seq( // msgpack-core should have no external dependencies - junitInterface, + junitJupiter, + junitVintage, "org.wvlet.airframe" %% "airframe-json" % AIRFRAME_VERSION % "test", "org.wvlet.airframe" %% "airspec" % AIRFRAME_VERSION % "test", // Add property testing support with forAll methods @@ -110,7 +112,8 @@ lazy val msgpackJackson = ), libraryDependencies ++= Seq( "com.fasterxml.jackson.core" % "jackson-databind" % "2.18.2", - junitInterface, + junitJupiter, + junitVintage, "org.apache.commons" % "commons-math3" % "3.6.1" % "test" ), testOptions += Tests.Argument(TestFrameworks.JUnit, "-v") diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatForFieldIdTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatForFieldIdTest.java index 0e102ba8..bbac6fb9 100644 --- a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatForFieldIdTest.java +++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatForFieldIdTest.java @@ -33,9 +33,9 @@ import java.util.Map; import java.util.Set; import java.util.LinkedHashMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class MessagePackDataformatForFieldIdTest { diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatForPojoTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatForPojoTest.java index 52269a7d..e899e4f4 100644 --- a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatForPojoTest.java +++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatForPojoTest.java @@ -16,7 +16,7 @@ package org.msgpack.jackson.dataformat; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.nio.charset.Charset; @@ -24,9 +24,9 @@ import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.hamcrest.MatcherAssert.assertThat; public class MessagePackDataformatForPojoTest extends MessagePackDataformatTestBase diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackFactoryTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackFactoryTest.java index f8d7ac3c..9e376541 100644 --- a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackFactoryTest.java +++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackFactoryTest.java @@ -23,7 +23,7 @@ import com.fasterxml.jackson.databind.AnnotationIntrospector; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.msgpack.core.MessagePack; import java.io.IOException; @@ -35,8 +35,8 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.nullValue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.hamcrest.MatcherAssert.assertThat; public class MessagePackFactoryTest extends MessagePackDataformatTestBase diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackGeneratorTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackGeneratorTest.java index 7ba48a61..a13951b2 100644 --- a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackGeneratorTest.java +++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackGeneratorTest.java @@ -24,7 +24,7 @@ import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.module.SimpleModule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.msgpack.core.ExtensionTypeHeader; import org.msgpack.core.MessagePack; import org.msgpack.core.MessageUnpacker; @@ -53,13 +53,14 @@ import java.util.concurrent.TimeUnit; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.hamcrest.MatcherAssert.assertThat; public class MessagePackGeneratorTest extends MessagePackDataformatTestBase @@ -349,7 +350,7 @@ public void testBigDecimal() } } - @Test(expected = IOException.class) + @Test public void testEnableFeatureAutoCloseTarget() throws IOException { @@ -358,7 +359,9 @@ public void testEnableFeatureAutoCloseTarget() ObjectMapper objectMapper = new ObjectMapper(messagePackFactory); List integers = Arrays.asList(1); objectMapper.writeValue(out, integers); - objectMapper.writeValue(out, integers); + assertThrows(IOException.class, () -> { + objectMapper.writeValue(out, integers); + }); } @Test diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackMapperTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackMapperTest.java index 68721fce..d14f97f2 100644 --- a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackMapperTest.java +++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackMapperTest.java @@ -16,14 +16,14 @@ package org.msgpack.jackson.dataformat; import com.fasterxml.jackson.core.JsonProcessingException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; public class MessagePackMapperTest { diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackParserTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackParserTest.java index a416c92b..c0bab053 100644 --- a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackParserTest.java +++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackParserTest.java @@ -27,7 +27,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.module.SimpleModule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.msgpack.core.MessagePack; import org.msgpack.core.MessagePacker; import org.msgpack.value.ExtensionValue; @@ -52,10 +52,11 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.assertThrows; public class MessagePackParserTest extends MessagePackDataformatTestBase @@ -450,7 +451,7 @@ public void setup(File f) return tempFile; } - @Test(expected = IOException.class) + @Test public void testEnableFeatureAutoCloseSource() throws Exception { @@ -459,7 +460,9 @@ public void testEnableFeatureAutoCloseSource() FileInputStream in = new FileInputStream(tempFile); ObjectMapper objectMapper = new ObjectMapper(factory); objectMapper.readValue(in, new TypeReference>() {}); - objectMapper.readValue(in, new TypeReference>() {}); + assertThrows(IOException.class, () -> { + objectMapper.readValue(in, new TypeReference>() {}); + }); } @Test diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/TimestampExtensionModuleTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/TimestampExtensionModuleTest.java index 05851dbc..074d7bf5 100755 --- a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/TimestampExtensionModuleTest.java +++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/TimestampExtensionModuleTest.java @@ -16,8 +16,8 @@ package org.msgpack.jackson.dataformat; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.msgpack.core.MessagePack; import org.msgpack.core.MessagePacker; import org.msgpack.core.MessageUnpacker; @@ -26,7 +26,7 @@ import java.io.IOException; import java.time.Instant; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class TimestampExtensionModuleTest { @@ -46,7 +46,7 @@ private static class TripleInstants public Instant c; } - @Before + @BeforeEach public void setUp() throws Exception { diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/MessagePackDataformatHugeDataBenchmarkTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/MessagePackDataformatHugeDataBenchmarkTest.java index fea34fd8..8ae73d0b 100644 --- a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/MessagePackDataformatHugeDataBenchmarkTest.java +++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/MessagePackDataformatHugeDataBenchmarkTest.java @@ -19,7 +19,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.msgpack.jackson.dataformat.MessagePackFactory; import java.io.File; diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/MessagePackDataformatPojoBenchmarkTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/MessagePackDataformatPojoBenchmarkTest.java index 2713eaea..8042153d 100644 --- a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/MessagePackDataformatPojoBenchmarkTest.java +++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/MessagePackDataformatPojoBenchmarkTest.java @@ -17,7 +17,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.msgpack.jackson.dataformat.MessagePackFactory; import static org.msgpack.jackson.dataformat.MessagePackDataformatTestBase.NormalPojo; import static org.msgpack.jackson.dataformat.MessagePackDataformatTestBase.Suit; From faabef5592c6e25d750b28bc001131261b9fb5b9 Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Sat, 19 Jul 2025 18:40:00 +0200 Subject: [PATCH 10/43] Update airframe-json, airspec to 2025.1.14 (#889) --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index d4645a11..301b88b4 100644 --- a/build.sbt +++ b/build.sbt @@ -5,7 +5,7 @@ Global / concurrentRestrictions := Seq( Tags.limit(Tags.Test, 1) ) -val AIRFRAME_VERSION = "2025.1.1" +val AIRFRAME_VERSION = "2025.1.14" // Use dynamic snapshot version strings for non tagged versions ThisBuild / dynverSonatypeSnapshots := true From 7a31503f71a269fff6bb238858a169934316ecd6 Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Sat, 19 Jul 2025 18:40:10 +0200 Subject: [PATCH 11/43] Update sbt, scripted-plugin to 1.10.11 (#881) --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index 8fc29878..fa5667a7 100755 --- a/project/build.properties +++ b/project/build.properties @@ -1,2 +1,2 @@ -sbt.version=1.10.7 +sbt.version=1.10.11 From 5c57bcffc27c0f10a294d6b9e4fa8039d595820d Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 19 Jul 2025 09:41:32 -0700 Subject: [PATCH 12/43] Upgrade sbt to 1.11.3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update from sbt 1.10.11 to the latest stable version 1.11.3. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index fa5667a7..138bc7a5 100755 --- a/project/build.properties +++ b/project/build.properties @@ -1,2 +1,2 @@ -sbt.version=1.10.11 +sbt.version=1.11.3 From 83a18920dac1baa101b1063801560fb37cec2071 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 19 Jul 2025 10:11:44 -0700 Subject: [PATCH 13/43] Migrate from sbt-sonatype to built-in sonaRelease (#898) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update sbt-dynver to 5.1.1 Fixes #892 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Migrate from sbt-sonatype to built-in sonaRelease - Remove sbt-sonatype plugin dependency from project/plugins.sbt - Move publishing metadata from sonatype.sbt to build.sbt - Update publishTo configuration to use direct Sonatype URLs - Use built-in sbt functionality instead of plugin for Sonatype publishing 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Update to sbt 1.11.3 and fix publishTo configuration - Update sbt version to 1.11.3 for built-in localStaging support - Fix publishTo setting to use correct Sonatype Central URLs - Use localStaging.value for releases and central-snapshots for snapshots 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Format code with scalafmt and fix scalafmt configuration - Fix .scalafmt.conf with version 3.9.8 and scala213 dialect - Format Scala test code according to project style - Maintain 180 character line limit and alignment style 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Update GitHub Actions workflows for Sonatype Central migration - Fix secret names to use SONATYPE_USERNAME and SONATYPE_PASSWORD - Remove deprecated sonatypeBundleRelease command from release workflow - Consolidate release steps to use publishSigned with correct environment - Update both release.yml and snapshot.yml workflows 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Use sonaRelease command in release workflow - Replace publishSigned with sonaRelease for proper release flow - sonaRelease handles both publishing and release to Central Portal 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Add publishSigned step back to release workflow - First step: publishSigned to stage signed artifacts - Second step: sonaRelease to release staged artifacts to Central - Both steps needed for proper release flow 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Revert to original workflow structure with updated secrets - Restore "Build bundle" and "Release to Sonatype" step names - Keep publishSigned in Build bundle step - Use sonaRelease in Release step with correct secret names - Maintain original workflow structure with modern functionality 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --------- Co-authored-by: Claude --- .github/workflows/release.yml | 6 ++--- .github/workflows/snapshot.yml | 4 ++-- .scalafmt.conf | 2 ++ build.sbt | 24 ++++++++++++++++++- .../msgpack/core/InvalidDataReadTest.scala | 3 +-- .../org/msgpack/core/MessageFormatTest.scala | 3 +-- .../org/msgpack/core/MessagePackSpec.scala | 2 +- .../org/msgpack/core/MessagePackTest.scala | 23 +++++++++--------- .../org/msgpack/core/MessagePackerTest.scala | 15 ++++++------ .../msgpack/core/MessageUnpackerTest.scala | 4 ++-- .../core/buffer/MessageBufferInputTest.scala | 2 +- .../core/buffer/MessageBufferTest.scala | 3 +-- .../core/example/MessagePackExampleTest.scala | 3 +-- .../org/msgpack/value/ValueFactoryTest.scala | 3 +-- .../org/msgpack/value/ValueTypeTest.scala | 3 +-- .../org/msgpack/value/VariableTest.scala | 10 ++++---- project/plugins.sbt | 1 - sonatype.sbt | 18 -------------- 18 files changed, 62 insertions(+), 67 deletions(-) delete mode 100644 sonatype.sbt diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b214d8ec..c3dca7c2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,6 +33,6 @@ jobs: ./sbt publishSigned - name: Release to Sonatype env: - SONATYPE_USERNAME: '${{ secrets.SONATYPE_USER }}' - SONATYPE_PASSWORD: '${{ secrets.SONATYPE_PASS }}' - run: ./sbt sonatypeBundleRelease + SONATYPE_USERNAME: '${{ secrets.SONATYPE_USERNAME }}' + SONATYPE_PASSWORD: '${{ secrets.SONATYPE_PASSWORD }}' + run: ./sbt sonaRelease diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index cbce4c14..4cc85866 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -27,6 +27,6 @@ jobs: distribution: adopt - name: Publish snapshots env: - SONATYPE_USERNAME: '${{ secrets.SONATYPE_USER }}' - SONATYPE_PASSWORD: '${{ secrets.SONATYPE_PASS }}' + SONATYPE_USERNAME: '${{ secrets.SONATYPE_USERNAME }}' + SONATYPE_PASSWORD: '${{ secrets.SONATYPE_PASSWORD }}' run: ./sbt publish diff --git a/.scalafmt.conf b/.scalafmt.conf index bda502a5..eccdf1c2 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,3 +1,5 @@ +version = 3.9.8 +runner.dialect = scala213 maxColumn = 180 style = defaultWithAlign optIn.breaksInsideChains = true diff --git a/build.sbt b/build.sbt index 301b88b4..70c8161e 100644 --- a/build.sbt +++ b/build.sbt @@ -12,6 +12,24 @@ ThisBuild / dynverSonatypeSnapshots := true // Use coursier friendly version separator ThisBuild / dynverSeparator := "-" +// Publishing metadata +ThisBuild / homepage := Some(url("https://msgpack.org/")) +ThisBuild / licenses := Seq("Apache-2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0.txt")) +ThisBuild / scmInfo := Some( + ScmInfo( + url("https://github.com/msgpack/msgpack-java"), + "scm:git@github.com:msgpack/msgpack-java.git" + ) +) +ThisBuild / developers := List( + Developer(id = "frsyuki", name = "Sadayuki Furuhashi", email = "frsyuki@users.sourceforge.jp", url = url("https://github.com/frsyuki")), + Developer(id = "muga", name = "Muga Nishizawa", email = "muga.nishizawa@gmail.com", url = url("https://github.com/muga")), + Developer(id = "oza", name = "Tsuyoshi Ozawa", email = "ozawa.tsuyoshi@gmail.com", url = url("https://github.com/oza")), + Developer(id = "komamitsu", name = "Mitsunori Komatsu", email = "komamitsu@gmail.com", url = url("https://github.com/komamitsu")), + Developer(id = "xerial", name = "Taro L. Saito", email = "leo@xerial.org", url = url("https://github.com/xerial")) +) + + val buildSettings = Seq[Setting[_]]( organization := "org.msgpack", organizationName := "MessagePack", @@ -38,7 +56,11 @@ val buildSettings = Seq[Setting[_]]( } }, // Add sonatype repository settings - publishTo := sonatypePublishToBundle.value, + publishTo := { + val centralSnapshots = "https://central.sonatype.com/repository/maven-snapshots/" + if (isSnapshot.value) Some("central-snapshots" at centralSnapshots) + else localStaging.value + }, // Style check config: (sbt-jchekcstyle) jcheckStyleConfig := "facebook", // Run jcheckstyle both for main and test codes diff --git a/msgpack-core/src/test/scala/org/msgpack/core/InvalidDataReadTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/InvalidDataReadTest.scala index 6f013838..1c43bb33 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/InvalidDataReadTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/InvalidDataReadTest.scala @@ -3,8 +3,7 @@ package org.msgpack.core import org.msgpack.core.MessagePackSpec.createMessagePackData import wvlet.airspec.AirSpec -/** - */ +/** */ class InvalidDataReadTest extends AirSpec { test("Reading long EXT32") { diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessageFormatTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessageFormatTest.scala index 06a58e11..782b2e40 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessageFormatTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessageFormatTest.scala @@ -22,8 +22,7 @@ import wvlet.airspec.spi.AirSpecException import scala.util.Random -/** - * Created on 2014/05/07. +/** Created on 2014/05/07. */ class MessageFormatTest extends AirSpec with Benchmark { test("MessageFormat") { diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackSpec.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackSpec.scala index dee315cd..c4fb23b4 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackSpec.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackSpec.scala @@ -21,7 +21,7 @@ import wvlet.log.io.{TimeReport, Timer} import java.io.ByteArrayOutputStream object MessagePackSpec { - def toHex(arr: Array[Byte]) = arr.map(x => f"$x%02x").mkString(" ") + def toHex(arr: Array[Byte]) = arr.map(x => f"$x%02x").mkString(" ") def createMessagePackData(f: MessagePacker => Unit): Array[Byte] = { val b = new ByteArrayOutputStream() val packer = MessagePack.newDefaultPacker(b) diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala index c2993f96..0cec1b4b 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala @@ -30,8 +30,7 @@ import java.nio.charset.{CodingErrorAction, UnmappableCharacterException} import java.time.Instant import scala.util.Random -/** - * Created on 2014/05/07. +/** Created on 2014/05/07. */ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { @@ -396,7 +395,7 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { test("report errors when packing/unpacking malformed strings") { pending("We need to produce malformed utf-8 strings in Java 8") // Create 100 malformed UTF8 Strings - val r = new Random(0) + val r = new Random(0) val malformedStrings = Iterator .continually { val b = new Array[Byte](10) @@ -433,7 +432,7 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { test("report errors when packing/unpacking strings that contain unmappable characters") { val unmappable = Array[Byte](0xfc.toByte, 0x0a.toByte) - //val unmappableChar = Array[Char](new Character(0xfc0a).toChar) + // val unmappableChar = Array[Char](new Character(0xfc0a).toChar) // Report error on unmappable character val unpackerConfig = new UnpackerConfig() @@ -534,10 +533,9 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { m, { packer => packer.packMapHeader(v.length) - m.map { - case (k: Int, v: String) => - packer.packInt(k) - packer.packString(v) + m.map { case (k: Int, v: String) => + packer.packInt(k) + packer.packString(v) } }, { unpacker => @@ -666,13 +664,14 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { val posLong = Gen.chooseNum[Long](-31557014167219200L, 31556889864403199L) forAll(posLong) { (millis: Long) => val v = Instant.ofEpochMilli(millis) - check(v, { _.packTimestamp(millis) }, + check( + v, + { _.packTimestamp(millis) }, { u => val extHeader = u.unpackExtensionTypeHeader() - if(extHeader.isTimestampType) { + if (extHeader.isTimestampType) { u.unpackTimestamp(extHeader) - } - else { + } else { fail("Cannot reach here") } } diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala index dea3e4ea..7d762149 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala @@ -24,8 +24,7 @@ import wvlet.log.io.IOUtil.withResource import java.io.{ByteArrayOutputStream, File, FileInputStream, FileOutputStream} import scala.util.Random -/** - */ +/** */ class MessagePackerTest extends AirSpec with Benchmark { private def verifyIntSeq(answer: Array[Int], packed: Array[Byte]): Unit = { @@ -141,8 +140,8 @@ class MessagePackerTest extends AirSpec with Benchmark { 32 -> 31, 34 -> 32 ) - testCases.foreach { - case (bufferSize, stringSize) => test(bufferSize, stringSize) + testCases.foreach { case (bufferSize, stringSize) => + test(bufferSize, stringSize) } } @@ -234,7 +233,7 @@ class MessagePackerTest extends AirSpec with Benchmark { } test("compute totalWrittenBytes") { - val out = new ByteArrayOutputStream + val out = new ByteArrayOutputStream val packerTotalWrittenBytes = withResource(MessagePack.newDefaultPacker(out)) { packer => packer @@ -255,7 +254,7 @@ class MessagePackerTest extends AirSpec with Benchmark { test("support read-only buffer") { val payload = Array[Byte](1) val out = new ByteArrayOutputStream() - val packer = MessagePack + val packer = MessagePack .newDefaultPacker(out) .packBinaryHeader(1) .writePayload(payload) @@ -299,14 +298,14 @@ class MessagePackerTest extends AirSpec with Benchmark { test("write raw binary") { val packer = new MessagePack.PackerConfig().newBufferPacker() - val msg = + val msg = Array[Byte](-127, -92, 116, 121, 112, 101, -92, 112, 105, 110, 103) packer.writePayload(msg) } test("append raw binary") { val packer = new MessagePack.PackerConfig().newBufferPacker() - val msg = + val msg = Array[Byte](-127, -92, 116, 121, 112, 101, -92, 112, 105, 110, 103) packer.addPayload(msg) } diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala index 3ea5e911..620e7dbe 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala @@ -30,7 +30,7 @@ import scala.util.Random object MessageUnpackerTest { class SplitMessageBufferInput(array: Array[Array[Byte]]) extends MessageBufferInput { - var cursor = 0 + var cursor = 0 override def next(): MessageBuffer = { if (cursor < array.length) { val a = array(cursor) @@ -49,7 +49,7 @@ import org.msgpack.core.MessageUnpackerTest._ class MessageUnpackerTest extends AirSpec with Benchmark { - private val universal = MessageBuffer.allocate(0).isInstanceOf[MessageBufferU] + private val universal = MessageBuffer.allocate(0).isInstanceOf[MessageBufferU] private def testData: Array[Byte] = { val out = new ByteArrayOutputStream() val packer = MessagePack.newDefaultPacker(out) diff --git a/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferInputTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferInputTest.scala index dd1cdb97..a43704fb 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferInputTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferInputTest.scala @@ -33,7 +33,7 @@ class MessageBufferInputTest extends AirSpec { Seq(0, 10, 500, 1000, 2000, 4000, 8000, 10000, 30000, 50000, 100000) private def testData(size: Int): Array[Byte] = { - //debug(s"test data size: ${size}") + // debug(s"test data size: ${size}") val b = new Array[Byte](size) Random.nextBytes(b) b diff --git a/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferTest.scala index 4de05995..03e93b89 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferTest.scala @@ -21,8 +21,7 @@ import wvlet.airspec.AirSpec import java.nio.ByteBuffer import scala.util.Random -/** - * Created on 2014/05/01. +/** Created on 2014/05/01. */ class MessageBufferTest extends AirSpec with Benchmark { diff --git a/msgpack-core/src/test/scala/org/msgpack/core/example/MessagePackExampleTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/example/MessagePackExampleTest.scala index 99876275..d0b0e08e 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/example/MessagePackExampleTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/example/MessagePackExampleTest.scala @@ -17,8 +17,7 @@ package org.msgpack.core.example import wvlet.airspec.AirSpec -/** - */ +/** */ class MessagePackExampleTest extends AirSpec { test("example") { diff --git a/msgpack-core/src/test/scala/org/msgpack/value/ValueFactoryTest.scala b/msgpack-core/src/test/scala/org/msgpack/value/ValueFactoryTest.scala index 3fe2a07f..3568ba5b 100644 --- a/msgpack-core/src/test/scala/org/msgpack/value/ValueFactoryTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/value/ValueFactoryTest.scala @@ -19,8 +19,7 @@ import org.scalacheck.Gen import wvlet.airspec.AirSpec import wvlet.airspec.spi.PropertyCheck -/** - */ +/** */ class ValueFactoryTest extends AirSpec with PropertyCheck { private def isValid( diff --git a/msgpack-core/src/test/scala/org/msgpack/value/ValueTypeTest.scala b/msgpack-core/src/test/scala/org/msgpack/value/ValueTypeTest.scala index e8b04d5f..fc81bdeb 100644 --- a/msgpack-core/src/test/scala/org/msgpack/value/ValueTypeTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/value/ValueTypeTest.scala @@ -19,8 +19,7 @@ import org.msgpack.core.MessagePack.Code._ import org.msgpack.core.{MessageFormat, MessageFormatException} import wvlet.airspec.AirSpec -/** - * Created on 2014/05/06. +/** Created on 2014/05/06. */ class ValueTypeTest extends AirSpec { diff --git a/msgpack-core/src/test/scala/org/msgpack/value/VariableTest.scala b/msgpack-core/src/test/scala/org/msgpack/value/VariableTest.scala index 5d97d871..f9a1c2a0 100644 --- a/msgpack-core/src/test/scala/org/msgpack/value/VariableTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/value/VariableTest.scala @@ -23,8 +23,7 @@ import java.time.Instant import java.util import scala.jdk.CollectionConverters._ -/** - */ +/** */ class VariableTest extends AirSpec with PropertyCheck { private def check(pack: MessagePacker => Unit, checker: Variable => Unit): Unit = { val packer = MessagePack.newDefaultBufferPacker() @@ -38,8 +37,7 @@ class VariableTest extends AirSpec with PropertyCheck { unpacker.close() } - /** - * Test Value -> MsgPack -> Value + /** Test Value -> MsgPack -> Value */ private def roundTrip(v: Value): Unit = { val packer = MessagePack.newDefaultBufferPacker() @@ -210,8 +208,8 @@ class VariableTest extends AirSpec with PropertyCheck { _.packDouble(x), checker = { v => val iv = validateValue(v.asFloatValue(), asFloat = true) - //iv.toDouble shouldBe v - //iv.toFloat shouldBe x.toFloat + // iv.toDouble shouldBe v + // iv.toFloat shouldBe x.toFloat } ) } diff --git a/project/plugins.sbt b/project/plugins.sbt index d6844375..5bc49937 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,4 +1,3 @@ -addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.12.2") addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.1") // TODO: Fixes jacoco error: // java.lang.NoClassDefFoundError: Could not initialize class org.jacoco.core.internal.flow.ClassProbesAdapter diff --git a/sonatype.sbt b/sonatype.sbt deleted file mode 100644 index 3fcb592f..00000000 --- a/sonatype.sbt +++ /dev/null @@ -1,18 +0,0 @@ -import xerial.sbt.Sonatype._ - -ThisBuild / sonatypeProfileName := "org.msgpack" -ThisBuild / homepage := Some(url("https://msgpack.org/")) -ThisBuild / licenses := Seq("Apache-2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0.txt")) -ThisBuild / scmInfo := Some( - ScmInfo( - url("https://github.com/msgpack/msgpack-java"), - "scm:git@github.com:msgpack/msgpack-java.git" - ) -) -ThisBuild / developers := List( - Developer(id = "frsyuki", name = "Sadayuki Furuhashi", email = "frsyuki@users.sourceforge.jp", url = url("https://github.com/frsyuki")), - Developer(id = "muga", name = "Muga Nishizawa", email = "muga.nishizawa@gmail.com", url = url("https://github.com/muga")), - Developer(id = "oza", name = "Tsuyoshi Ozawa", email = "ozawa.tsuyoshi@gmail.com", url = url("https://github.com/oza")), - Developer(id = "komamitsu", name = "Mitsunori Komatsu", email = "komamitsu@gmail.com", url = url("https://github.com/komamitsu")), - Developer(id = "xerial", name = "Taro L. Saito", email = "leo@xerial.org", url = url("https://github.com/xerial")) -) From 4bcc43e5e539fdc05cc790852f82fb53618892dd Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 19 Jul 2025 10:24:00 -0700 Subject: [PATCH 14/43] Upgrade Scala to 3.7.1 and update code format style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Upgrade Scala version from 2.13.12 to 3.7.1 in build.sbt - Update scalafmt.conf to use Scala 3 dialect and modern formatting rules - Fix Scala 3 compatibility issues in test files: - Update lambda syntax to use parentheses around parameters - Remove deprecated underscore suffix from function references - Apply Scala 3 formatting with scalafmt 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .scalafmt.conf | 18 +- build.sbt | 2 +- .../msgpack/core/InvalidDataReadTest.scala | 18 +- .../core/MessageBufferPackerTest.scala | 5 +- .../org/msgpack/core/MessageFormatTest.scala | 45 +- .../org/msgpack/core/MessagePackSpec.scala | 26 +- .../org/msgpack/core/MessagePackTest.scala | 312 +++++---- .../org/msgpack/core/MessagePackerTest.scala | 151 ++--- .../msgpack/core/MessageUnpackerTest.scala | 628 +++++++++--------- .../org/msgpack/core/StringLimitTest.scala | 5 +- .../msgpack/core/buffer/ByteStringTest.scala | 29 +- .../core/buffer/DirectBufferAccessTest.scala | 3 +- .../core/buffer/MessageBufferInputTest.scala | 128 ++-- .../core/buffer/MessageBufferOutputTest.scala | 19 +- .../core/buffer/MessageBufferTest.scala | 95 ++- .../core/example/MessagePackExampleTest.scala | 6 +- .../value/RawStringValueImplTest.scala | 3 +- .../org/msgpack/value/ValueFactoryTest.scala | 60 +- .../scala/org/msgpack/value/ValueTest.scala | 25 +- .../org/msgpack/value/ValueTypeTest.scala | 49 +- .../org/msgpack/value/VariableTest.scala | 226 +++---- 21 files changed, 904 insertions(+), 949 deletions(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index eccdf1c2..fcadd98d 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,5 +1,17 @@ -version = 3.9.8 -runner.dialect = scala213 -maxColumn = 180 +version = 3.9.4 +project.layout = StandardConvention +runner.dialect = scala3 +maxColumn = 100 style = defaultWithAlign +docstrings.blankFirstLine = yes +rewrite.scala3.convertToNewSyntax = true +rewrite.scala3.removeOptionalBraces = yes +rewrite.scala3.insertEndMarkerMinLines = 30 +# Add a new line before case class +newlines.topLevelStatementBlankLines = [ + { + blanks { after = 1 } + } +] +newlines.source = unfold optIn.breaksInsideChains = true diff --git a/build.sbt b/build.sbt index 70c8161e..3d6ba320 100644 --- a/build.sbt +++ b/build.sbt @@ -35,7 +35,7 @@ val buildSettings = Seq[Setting[_]]( organizationName := "MessagePack", organizationHomepage := Some(url("http://msgpack.org/")), description := "MessagePack for Java", - scalaVersion := "2.13.12", + scalaVersion := "3.7.1", Test / logBuffered := false, // msgpack-java should be a pure-java library, so remove Scala specific configurations autoScalaLibrary := false, diff --git a/msgpack-core/src/test/scala/org/msgpack/core/InvalidDataReadTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/InvalidDataReadTest.scala index 1c43bb33..76f04c97 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/InvalidDataReadTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/InvalidDataReadTest.scala @@ -3,21 +3,21 @@ package org.msgpack.core import org.msgpack.core.MessagePackSpec.createMessagePackData import wvlet.airspec.AirSpec -/** */ -class InvalidDataReadTest extends AirSpec { +/** + */ +class InvalidDataReadTest extends AirSpec: test("Reading long EXT32") { // Prepare an EXT32 data with 2GB (Int.MaxValue size) payload for testing the behavior of MessageUnpacker.skipValue() // Actually preparing 2GB of data, however, is too much for CI, so we create only the header part. - val msgpack = createMessagePackData(p => p.packExtensionTypeHeader(MessagePack.Code.EXT32, Int.MaxValue)) - val u = MessagePack.newDefaultUnpacker(msgpack) - try { + val msgpack = createMessagePackData(p => + p.packExtensionTypeHeader(MessagePack.Code.EXT32, Int.MaxValue) + ) + val u = MessagePack.newDefaultUnpacker(msgpack) + try // This error will be thrown after reading the header as the input has no EXT32 body intercept[MessageInsufficientBufferException] { u.skipValue() } - } finally { - u.close() - } + finally u.close() } -} diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessageBufferPackerTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessageBufferPackerTest.scala index 58b29f43..f4b74986 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessageBufferPackerTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessageBufferPackerTest.scala @@ -17,10 +17,10 @@ package org.msgpack.core import java.io.ByteArrayOutputStream import java.util.Arrays -import org.msgpack.value.ValueFactory._ +import org.msgpack.value.ValueFactory.* import wvlet.airspec.AirSpec -class MessageBufferPackerTest extends AirSpec { +class MessageBufferPackerTest extends AirSpec: test("MessageBufferPacker") { test("be equivalent to ByteArrayOutputStream") { val packer1 = MessagePack.newDefaultBufferPacker @@ -48,4 +48,3 @@ class MessageBufferPackerTest extends AirSpec { } } -} diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessageFormatTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessageFormatTest.scala index 782b2e40..a626978d 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessageFormatTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessageFormatTest.scala @@ -22,48 +22,41 @@ import wvlet.airspec.spi.AirSpecException import scala.util.Random -/** Created on 2014/05/07. +/** + * Created on 2014/05/07. */ -class MessageFormatTest extends AirSpec with Benchmark { +class MessageFormatTest extends AirSpec with Benchmark: test("MessageFormat") { test("cover all byte codes") { - def checkV(b: Byte, tpe: ValueType): Unit = { - try MessageFormat.valueOf(b).getValueType shouldBe tpe - catch { + def checkV(b: Byte, tpe: ValueType): Unit = + try + MessageFormat.valueOf(b).getValueType shouldBe tpe + catch case e: AirSpecException => error(f"Failure when looking at byte ${b}%02x") throw e - } - } - def checkF(b: Byte, f: MessageFormat): Unit = { - MessageFormat.valueOf(b) shouldBe f - } + def checkF(b: Byte, f: MessageFormat): Unit = MessageFormat.valueOf(b) shouldBe f - def check(b: Byte, tpe: ValueType, f: MessageFormat): Unit = { + def check(b: Byte, tpe: ValueType, f: MessageFormat): Unit = checkV(b, tpe) checkF(b, f) - } - for (i <- 0 until 0x7f) { + for i <- 0 until 0x7f do check(i.toByte, ValueType.INTEGER, MessageFormat.POSFIXINT) - } - for (i <- 0x80 until 0x8f) { + for i <- 0x80 until 0x8f do check(i.toByte, ValueType.MAP, MessageFormat.FIXMAP) - } - for (i <- 0x90 until 0x9f) { + for i <- 0x90 until 0x9f do check(i.toByte, ValueType.ARRAY, MessageFormat.FIXARRAY) - } check(Code.NIL, ValueType.NIL, MessageFormat.NIL) MessageFormat.valueOf(Code.NEVER_USED) shouldBe MessageFormat.NEVER_USED - for (i <- Seq(Code.TRUE, Code.FALSE)) { + for i <- Seq(Code.TRUE, Code.FALSE) do check(i, ValueType.BOOLEAN, MessageFormat.BOOLEAN) - } check(Code.BIN8, ValueType.BINARY, MessageFormat.BIN8) check(Code.BIN16, ValueType.BINARY, MessageFormat.BIN16) @@ -97,9 +90,8 @@ class MessageFormatTest extends AirSpec with Benchmark { check(Code.ARRAY16, ValueType.ARRAY, MessageFormat.ARRAY16) check(Code.ARRAY32, ValueType.ARRAY, MessageFormat.ARRAY32) - for (i <- 0xe0 to 0xff) { + for i <- 0xe0 to 0xff do check(i.toByte, ValueType.INTEGER, MessageFormat.NEGFIXINT) - } } test("improve the valueOf performance") { @@ -112,20 +104,19 @@ class MessageFormatTest extends AirSpec with Benchmark { time("lookup", repeat = 10) { block("switch") { var i = 0 - while (i < N) { + while i < N do MessageFormat.toMessageFormat(idx(i)) i += 1 - } } block("table") { var i = 0 - while (i < N) { + while i < N do MessageFormat.valueOf(idx(i)) i += 1 - } } } } } -} + +end MessageFormatTest diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackSpec.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackSpec.scala index c4fb23b4..135c4921 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackSpec.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackSpec.scala @@ -20,31 +20,29 @@ import wvlet.log.io.{TimeReport, Timer} import java.io.ByteArrayOutputStream -object MessagePackSpec { - def toHex(arr: Array[Byte]) = arr.map(x => f"$x%02x").mkString(" ") - def createMessagePackData(f: MessagePacker => Unit): Array[Byte] = { +object MessagePackSpec: + def toHex(arr: Array[Byte]) = arr.map(x => f"$x%02x").mkString(" ") + def createMessagePackData(f: MessagePacker => Unit): Array[Byte] = val b = new ByteArrayOutputStream() val packer = MessagePack.newDefaultPacker(b) f(packer) packer.close() b.toByteArray - } -} -trait Benchmark extends Timer { +trait Benchmark extends Timer: private val numWarmUpRuns = 10 - override protected def time[A](blockName: String, logLevel: LogLevel = LogLevel.INFO, repeat: Int = 1, blockRepeat: Int = 1)(f: => A): TimeReport = { - super.time(blockName, logLevel = LogLevel.INFO, repeat)(f) - } + override protected def time[A]( + blockName: String, + logLevel: LogLevel = LogLevel.INFO, + repeat: Int = 1, + blockRepeat: Int = 1 + )(f: => A): TimeReport = super.time(blockName, logLevel = LogLevel.INFO, repeat)(f) - override protected def block[A](name: String)(f: => A): TimeReport = { + override protected def block[A](name: String)(f: => A): TimeReport = var i = 0 - while (i < numWarmUpRuns) { + while i < numWarmUpRuns do f i += 1 - } super.block(name)(f) - } -} diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala index 0cec1b4b..0a4328d8 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala @@ -30,27 +30,26 @@ import java.nio.charset.{CodingErrorAction, UnmappableCharacterException} import java.time.Instant import scala.util.Random -/** Created on 2014/05/07. +/** + * Created on 2014/05/07. */ -class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { +class MessagePackTest extends AirSpec with PropertyCheck with Benchmark: - private def isValidUTF8(s: String) = { - MessagePack.UTF8.newEncoder().canEncode(s) - } + private def isValidUTF8(s: String) = MessagePack.UTF8.newEncoder().canEncode(s) - private def containsUnmappableCharacter(s: String): Boolean = { - try { - MessagePack.UTF8 + private def containsUnmappableCharacter(s: String): Boolean = + try + MessagePack + .UTF8 .newEncoder() .onUnmappableCharacter(CodingErrorAction.REPORT) .encode(CharBuffer.wrap(s)) false - } catch { + catch case e: UnmappableCharacterException => true - case _: Exception => false - } - } + case _: Exception => + false test("clone packer config") { val config = new PackerConfig() @@ -77,13 +76,11 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { test("detect fixint values") { - for (i <- 0 until 0x7f) { + for i <- 0 until 0x7f do Code.isPosFixInt(i.toByte) shouldBe true - } - for (i <- 0x80 until 0xff) { + for i <- 0x80 until 0xff do Code.isPosFixInt(i.toByte) shouldBe false - } } test("detect fixarray values") { @@ -92,12 +89,11 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { packer.close val bytes = packer.toByteArray MessagePack.newDefaultUnpacker(bytes).unpackArrayHeader() shouldBe 0 - try { + try MessagePack.newDefaultUnpacker(bytes).unpackMapHeader() fail("Shouldn't reach here") - } catch { + catch case e: MessageTypeException => // OK - } } test("detect fixmap values") { @@ -106,12 +102,11 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { packer.close val bytes = packer.toByteArray MessagePack.newDefaultUnpacker(bytes).unpackMapHeader() shouldBe 0 - try { + try MessagePack.newDefaultUnpacker(bytes).unpackArrayHeader() fail("Shouldn't reach here") - } catch { + catch case e: MessageTypeException => // OK - } } test("detect fixint quickly") { @@ -124,34 +119,28 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { block("mask") { var i = 0 var count = 0 - while (i < N) { - if ((idx(i) & Code.POSFIXINT_MASK) == 0) { + while i < N do + if (idx(i) & Code.POSFIXINT_MASK) == 0 then count += 1 - } i += 1 - } } block("mask in func") { var i = 0 var count = 0 - while (i < N) { - if (Code.isPosFixInt(idx(i))) { + while i < N do + if Code.isPosFixInt(idx(i)) then count += 1 - } i += 1 - } } block("shift cmp") { var i = 0 var count = 0 - while (i < N) { - if ((idx(i) >>> 7) == 0) { + while i < N do + if (idx(i) >>> 7) == 0 then count += 1 - } i += 1 - } } @@ -161,13 +150,11 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { test("detect neg fix int values") { - for (i <- 0 until 0xe0) { + for i <- 0 until 0xe0 do Code.isNegFixInt(i.toByte) shouldBe false - } - for (i <- 0xe0 until 0xff) { + for i <- 0xe0 until 0xff do Code.isNegFixInt(i.toByte) shouldBe true - } } @@ -177,9 +164,9 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { unpack: MessageUnpacker => A, packerConfig: PackerConfig = new PackerConfig(), unpackerConfig: UnpackerConfig = new UnpackerConfig() - ): Boolean = { + ): Boolean = var b: Array[Byte] = null - try { + try val bs = new ByteArrayOutputStream() val packer = packerConfig.newPacker(bs) pack(packer) @@ -191,15 +178,12 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { val ret = unpack(unpacker) ret shouldBe v true - } catch { + catch case e: Exception => warn(e.getMessage) - if (b != null) { + if b != null then warn(s"packed data (size:${b.length}): ${toHex(b)}") - } throw e - } - } private def checkException[A]( v: A, @@ -207,7 +191,7 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { unpack: MessageUnpacker => A, packerConfig: PackerConfig = new PackerConfig(), unpaackerConfig: UnpackerConfig = new UnpackerConfig() - ): Unit = { + ): Unit = var b: Array[Byte] = null val bs = new ByteArrayOutputStream() val packer = packerConfig.newPacker(bs) @@ -220,15 +204,16 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { val ret = unpack(unpacker) fail("cannot not reach here") - } - private def checkOverflow[A](v: A, pack: MessagePacker => Unit, unpack: MessageUnpacker => A): Unit = { - try { + private def checkOverflow[A]( + v: A, + pack: MessagePacker => Unit, + unpack: MessageUnpacker => A + ): Unit = + try checkException[A](v, pack, unpack) - } catch { + catch case e: MessageIntegerOverflowException => // OK - } - } test("pack/unpack primitive values") { forAll { (v: Boolean) => @@ -256,7 +241,8 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { null, _.packNil, { unpacker => - unpacker.unpackNil(); null + unpacker.unpackNil(); + null } ) } @@ -278,29 +264,35 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { packer.packString("val") }, { unpacker => - unpacker.tryUnpackNil(); unpacker.unpackString() + unpacker.tryUnpackNil(); + unpacker.unpackString() } ) check( "val", { packer => - packer.packNil(); packer.packString("val") + packer.packNil(); + packer.packString("val") }, { unpacker => - unpacker.tryUnpackNil(); unpacker.unpackString() + unpacker.tryUnpackNil(); + unpacker.unpackString() } ) - try { - checkException(null, { _ => }, _.tryUnpackNil) - } catch { + try + checkException( + null, + { _ => + }, + _.tryUnpackNil + ) + catch case e: MessageInsufficientBufferException => // OK - } } test("pack/unpack integer values") { val sampleData = Seq[Long]( - Int.MinValue.toLong - - 10, + Int.MinValue.toLong - 10, -65535, -8191, -1024, @@ -326,31 +318,26 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { 65536, Int.MaxValue.toLong + 10 ) - for (v <- sampleData) { + for v <- sampleData do check(v, _.packLong(v), _.unpackLong) - if (v.isValidInt) { + if v.isValidInt then val vi = v.toInt check(vi, _.packInt(vi), _.unpackInt) - } else { + else checkOverflow(v, _.packLong(v), _.unpackInt) - } - if (v.isValidShort) { + if v.isValidShort then val vi = v.toShort check(vi, _.packShort(vi), _.unpackShort) - } else { + else checkOverflow(v, _.packLong(v), _.unpackShort) - } - if (v.isValidByte) { + if v.isValidByte then val vi = v.toByte check(vi, _.packByte(vi), _.unpackByte) - } else { + else checkOverflow(v, _.packLong(v), _.unpackByte) - } - - } } @@ -360,23 +347,19 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { check(v, _.packBigInteger(v), _.unpackBigInteger) } - for (bi <- Seq(BigInteger.valueOf(Long.MaxValue).add(BigInteger.valueOf(1)))) { + for bi <- Seq(BigInteger.valueOf(Long.MaxValue).add(BigInteger.valueOf(1))) do check(bi, _.packBigInteger(bi), _.unpackBigInteger()) - } - for (bi <- Seq(BigInteger.valueOf(Long.MaxValue).shiftLeft(10))) { - try { + for bi <- Seq(BigInteger.valueOf(Long.MaxValue).shiftLeft(10)) do + try checkException(bi, _.packBigInteger(bi), _.unpackBigInteger()) fail("cannot reach here") - } catch { + catch case e: IllegalArgumentException => // OK - } - } - } test("pack/unpack strings") { - val utf8Strings = Arbitrary.arbitrary[String].suchThat(isValidUTF8 _) + val utf8Strings = Arbitrary.arbitrary[String].suchThat(isValidUTF8) utf8Strings.map { v => check(v, _.packString(v), _.unpackString) } @@ -385,17 +368,15 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { test("pack/unpack large strings") { // Large string val strLen = Seq(1000, 2000, 10000, 50000, 100000, 500000) - for (l <- strLen) { - val v: String = - Iterator.continually(Random.nextString(l * 10)).find(isValidUTF8).get + for l <- strLen do + val v: String = Iterator.continually(Random.nextString(l * 10)).find(isValidUTF8).get check(v, _.packString(v), _.unpackString) - } } test("report errors when packing/unpacking malformed strings") { pending("We need to produce malformed utf-8 strings in Java 8") // Create 100 malformed UTF8 Strings - val r = new Random(0) + val r = new Random(0) val malformedStrings = Iterator .continually { val b = new Array[Byte](10) @@ -405,16 +386,14 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { .filter(b => !isValidUTF8(new String(b))) .take(100) - for (malformedBytes <- malformedStrings) { + for malformedBytes <- malformedStrings do // Pack tests val malformed = new String(malformedBytes) - try { + try checkException(malformed, _.packString(malformed), _.unpackString()) - } catch { + catch case e: MessageStringCodingException => // OK - } - - try { + try checkException( malformed, { packer => @@ -423,10 +402,8 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { }, _.unpackString() ) - } catch { + catch case e: MessageStringCodingException => // OK - } - } } test("report errors when packing/unpacking strings that contain unmappable characters") { @@ -439,8 +416,8 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { .withActionOnMalformedString(CodingErrorAction.REPORT) .withActionOnUnmappableString(CodingErrorAction.REPORT) - for (bytes <- Seq(unmappable)) { - try { + for bytes <- Seq(unmappable) do + try checkException( bytes, { packer => @@ -451,10 +428,8 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { new PackerConfig(), unpackerConfig ) - } catch { + catch case e: MessageStringCodingException => // OK - } - } } test("pack/unpack binary") { @@ -462,7 +437,8 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { check( v, { packer => - packer.packBinaryHeader(v.length); packer.writePayload(v) + packer.packBinaryHeader(v.length); + packer.writePayload(v) }, { unpacker => val len = unpacker.unpackBinaryHeader() @@ -474,13 +450,14 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { } val len = Seq(1000, 2000, 10000, 50000, 100000, 500000) - for (l <- len) { + for l <- len do val v = new Array[Byte](l) Random.nextBytes(v) check( v, { packer => - packer.packBinaryHeader(v.length); packer.writePayload(v) + packer.packBinaryHeader(v.length); + packer.writePayload(v) }, { unpacker => val len = unpacker.unpackBinaryHeader() @@ -489,10 +466,11 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { out } ) - } } - val testHeaderLength = Seq(1, 2, 4, 8, 16, 17, 32, 64, 255, 256, 1000, 2000, 10000, 50000, 100000, 500000) + val testHeaderLength = Seq( + 1, 2, 4, 8, 16, 17, 32, 64, 255, 256, 1000, 2000, 10000, 50000, 100000, 500000 + ) test("pack/unpack arrays") { forAll { (v: Array[Int]) => @@ -505,24 +483,20 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { { unpacker => val len = unpacker.unpackArrayHeader() val out = new Array[Int](len) - for (i <- 0 until v.length) { + for i <- 0 until v.length do out(i) = unpacker.unpackInt - } out } ) } - for (l <- testHeaderLength) { + for l <- testHeaderLength do check(l, _.packArrayHeader(l), _.unpackArrayHeader()) - } - try { + try checkException(0, _.packArrayHeader(-1), _.unpackArrayHeader) - } catch { + catch case e: IllegalArgumentException => // OK - } - } test("pack/unpack maps") { @@ -541,40 +515,43 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { { unpacker => val len = unpacker.unpackMapHeader() val b = Seq.newBuilder[(Int, String)] - for (i <- 0 until len) { + for i <- 0 until len do b += ((unpacker.unpackInt, unpacker.unpackString)) - } b.result() } ) } - for (l <- testHeaderLength) { + for l <- testHeaderLength do check(l, _.packMapHeader(l), _.unpackMapHeader()) - } - try { + try checkException(0, _.packMapHeader(-1), _.unpackMapHeader) - } catch { + catch case e: IllegalArgumentException => // OK - } - } test("pack/unpack extension types") { forAll { (dataLen: Int, tpe: Byte) => val l = Math.abs(dataLen) l >= 0 ==> { - val ext = - new ExtensionTypeHeader(ExtensionTypeHeader.checkedCastToByte(tpe), l) - check(ext, _.packExtensionTypeHeader(ext.getType, ext.getLength), _.unpackExtensionTypeHeader()) + val ext = new ExtensionTypeHeader(ExtensionTypeHeader.checkedCastToByte(tpe), l) + check( + ext, + _.packExtensionTypeHeader(ext.getType, ext.getLength), + _.unpackExtensionTypeHeader() + ) } } - for (l <- testHeaderLength) { - val ext = new ExtensionTypeHeader(ExtensionTypeHeader.checkedCastToByte(Random.nextInt(128)), l) - check(ext, _.packExtensionTypeHeader(ext.getType, ext.getLength), _.unpackExtensionTypeHeader()) - } + for l <- testHeaderLength do + val ext = + new ExtensionTypeHeader(ExtensionTypeHeader.checkedCastToByte(Random.nextInt(128)), l) + check( + ext, + _.packExtensionTypeHeader(ext.getType, ext.getLength), + _.unpackExtensionTypeHeader() + ) } @@ -585,31 +562,30 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { aMap, { packer => packer.packArrayHeader(aMap.size) - for (m <- aMap) { + for m <- aMap do packer.packMapHeader(m.size) - for ((k, v) <- m) { + for (k, v) <- m do packer.packString(k) packer.packString(v) - } - } }, { unpacker => val v = new Variable() unpacker.unpackValue(v) - import scala.jdk.CollectionConverters._ - v.asArrayValue().asScala + import scala.jdk.CollectionConverters.* + v.asArrayValue() + .asScala .map { m => val mv = m.asMapValue() val kvs = mv.getKeyValueArray kvs .grouped(2) - .map({ kvp: Array[Value] => + .map((kvp: Array[Value]) => val k = kvp(0) val v = kvp(1) (k.asStringValue().asString, v.asStringValue().asString) - }) + ) .toMap } .toList @@ -622,12 +598,24 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { val posInt = Gen.chooseNum(0, 1000000000 - 1) // NANOS_PER_SECOND forAll(posLong, posInt) { (second: Long, nano: Int) => val v = Instant.ofEpochSecond(second, nano) - check(v, { _.packTimestamp(v) }, { _.unpackTimestamp() }) + check( + v, { + _.packTimestamp(v) + }, { + _.unpackTimestamp() + } + ) } // Using different insterfaces forAll(posLong, posInt) { (second: Long, nano: Int) => val v = Instant.ofEpochSecond(second, nano) - check(v, { _.packTimestamp(second, nano) }, { _.unpackTimestamp() }) + check( + v, { + _.packTimestamp(second, nano) + }, { + _.unpackTimestamp() + } + ) } val secLessThan34bits = Gen.chooseNum[Long](0, 1L << 34) forAll(secLessThan34bits, posInt) { (second: Long, nano: Int) => @@ -640,23 +628,30 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { } // Corner-cases around uint32 boundaries - for ( - v <- Seq( - Instant.ofEpochSecond(Instant.now().getEpochSecond, 123456789L), // uint32 nanoseq (out of int32 range) - Instant.ofEpochSecond(-1302749144L, 0), // 1928-09-19T21:14:16Z - Instant.ofEpochSecond(-747359729L, 0), // 1946-04-27T00:04:31Z - Instant.ofEpochSecond(4257387427L, 0) // 2104-11-29T07:37:07Z + for v <- Seq( + Instant.ofEpochSecond( + Instant.now().getEpochSecond, + 123456789L + ), // uint32 nanoseq (out of int32 range) + Instant.ofEpochSecond(-1302749144L, 0), // 1928-09-19T21:14:16Z + Instant.ofEpochSecond(-747359729L, 0), // 1946-04-27T00:04:31Z + Instant.ofEpochSecond(4257387427L, 0) // 2104-11-29T07:37:07Z ) - ) { + do check(v, _.packTimestamp(v), _.unpackTimestamp()) - } } test("pack/unpack timestamp in millis") { val posLong = Gen.chooseNum[Long](-31557014167219200L, 31556889864403199L) forAll(posLong) { (millis: Long) => val v = Instant.ofEpochMilli(millis) - check(v, { _.packTimestamp(millis) }, { _.unpackTimestamp() }) + check( + v, { + _.packTimestamp(millis) + }, { + _.unpackTimestamp() + } + ) } } @@ -665,15 +660,15 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { forAll(posLong) { (millis: Long) => val v = Instant.ofEpochMilli(millis) check( - v, - { _.packTimestamp(millis) }, + v, { + _.packTimestamp(millis) + }, { u => val extHeader = u.unpackExtensionTypeHeader() - if (extHeader.isTimestampType) { + if extHeader.isTimestampType then u.unpackTimestamp(extHeader) - } else { + else fail("Cannot reach here") - } } ) } @@ -710,12 +705,11 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark { a.withBufferSize(64 * 1024).equals(b) shouldBe false a.withAllowReadingStringAsBinary(false).equals(b) shouldBe false a.withAllowReadingBinaryAsString(false).equals(b) shouldBe false - a.withActionOnMalformedString(CodingErrorAction.REPORT) - .equals(b) shouldBe false - a.withActionOnUnmappableString(CodingErrorAction.REPORT) - .equals(b) shouldBe false + a.withActionOnMalformedString(CodingErrorAction.REPORT).equals(b) shouldBe false + a.withActionOnUnmappableString(CodingErrorAction.REPORT).equals(b) shouldBe false a.withStringSizeLimit(32).equals(b) shouldBe false a.withStringDecoderBufferSize(32).equals(b) shouldBe false } } -} + +end MessagePackTest diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala index 7d762149..c1b4b0a4 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala @@ -24,37 +24,33 @@ import wvlet.log.io.IOUtil.withResource import java.io.{ByteArrayOutputStream, File, FileInputStream, FileOutputStream} import scala.util.Random -/** */ -class MessagePackerTest extends AirSpec with Benchmark { +/** + */ +class MessagePackerTest extends AirSpec with Benchmark: - private def verifyIntSeq(answer: Array[Int], packed: Array[Byte]): Unit = { + private def verifyIntSeq(answer: Array[Int], packed: Array[Byte]): Unit = val unpacker = MessagePack.newDefaultUnpacker(packed) val b = Array.newBuilder[Int] - while (unpacker.hasNext) { + while unpacker.hasNext do b += unpacker.unpackInt() - } val result = b.result() result.size shouldBe answer.size result shouldBe answer - } - private def createTempFile = { + private def createTempFile = val f = File.createTempFile("msgpackTest", "msgpack") f.deleteOnExit f - } - private def createTempFileWithOutputStream = { + private def createTempFileWithOutputStream = val f = createTempFile val out = new FileOutputStream(f) (f, out) - } - private def createTempFileWithChannel = { + private def createTempFileWithChannel = val (f, out) = createTempFileWithOutputStream val ch = out.getChannel (f, ch) - } test("MessagePacker") { @@ -69,16 +65,14 @@ class MessagePackerTest extends AirSpec with Benchmark { val intSeq2 = intSeq.reverse val b2 = new ByteArrayOutputStream - packer - .reset(new OutputStreamBufferOutput(b2)) + packer.reset(new OutputStreamBufferOutput(b2)) intSeq2 foreach packer.packInt packer.close verifyIntSeq(intSeq2, b2.toByteArray) val intSeq3 = intSeq2.sorted val b3 = new ByteArrayOutputStream - packer - .reset(new OutputStreamBufferOutput(b3)) + packer.reset(new OutputStreamBufferOutput(b3)) intSeq3 foreach packer.packInt packer.close verifyIntSeq(intSeq3, b3.toByteArray) @@ -86,43 +80,41 @@ class MessagePackerTest extends AirSpec with Benchmark { test("improve the performance via reset method") { val N = 1000 - val t = time("packer", repeat = 10) { - block("no-buffer-reset") { - val out = new ByteArrayOutputStream - withResource(MessagePack.newDefaultPacker(out)) { packer => - for (i <- 0 until N) { - val outputStream = new ByteArrayOutputStream() - packer - .reset(new OutputStreamBufferOutput(outputStream)) - packer.packInt(0) - packer.flush() + val t = + time("packer", repeat = 10) { + block("no-buffer-reset") { + val out = new ByteArrayOutputStream + withResource(MessagePack.newDefaultPacker(out)) { packer => + for i <- 0 until N do + val outputStream = new ByteArrayOutputStream() + packer.reset(new OutputStreamBufferOutput(outputStream)) + packer.packInt(0) + packer.flush() } } - } - block("buffer-reset") { - val out = new ByteArrayOutputStream - withResource(MessagePack.newDefaultPacker(out)) { packer => - val bufferOut = - new OutputStreamBufferOutput(new ByteArrayOutputStream()) - for (i <- 0 until N) { - val outputStream = new ByteArrayOutputStream() - bufferOut.reset(outputStream) - packer.reset(bufferOut) - packer.packInt(0) - packer.flush() + block("buffer-reset") { + val out = new ByteArrayOutputStream + withResource(MessagePack.newDefaultPacker(out)) { packer => + val bufferOut = new OutputStreamBufferOutput(new ByteArrayOutputStream()) + for i <- 0 until N do + val outputStream = new ByteArrayOutputStream() + bufferOut.reset(outputStream) + packer.reset(bufferOut) + packer.packInt(0) + packer.flush() } } } - } - t("buffer-reset").averageWithoutMinMax <= t("no-buffer-reset").averageWithoutMinMax shouldBe true + t("buffer-reset").averageWithoutMinMax <= t("no-buffer-reset").averageWithoutMinMax shouldBe + true } test("pack larger string array than byte buf") { // Based on https://github.com/msgpack/msgpack-java/issues/154 - def test(bufferSize: Int, stringSize: Int): Boolean = { + def test(bufferSize: Int, stringSize: Int): Boolean = val str = "a" * stringSize val rawString = ValueFactory.newString(str.getBytes("UTF-8")) val array = ValueFactory.newArray(rawString) @@ -132,14 +124,8 @@ class MessagePackerTest extends AirSpec with Benchmark { packer.close() out.toByteArray true - } - val testCases = Seq( - 32 -> 30, - 33 -> 31, - 32 -> 31, - 34 -> 32 - ) + val testCases = Seq(32 -> 30, 33 -> 31, 32 -> 31, 34 -> 32) testCases.foreach { case (bufferSize, stringSize) => test(bufferSize, stringSize) } @@ -151,24 +137,20 @@ class MessagePackerTest extends AirSpec with Benchmark { packer.packInt(99) packer.close - val up0 = MessagePack - .newDefaultUnpacker(new FileInputStream(f0)) + val up0 = MessagePack.newDefaultUnpacker(new FileInputStream(f0)) up0.unpackInt shouldBe 99 up0.hasNext shouldBe false up0.close val (f1, out1) = createTempFileWithOutputStream - packer - .reset(new OutputStreamBufferOutput(out1)) + packer.reset(new OutputStreamBufferOutput(out1)) packer.packInt(99) packer.flush - packer - .reset(new OutputStreamBufferOutput(out1)) + packer.reset(new OutputStreamBufferOutput(out1)) packer.packString("hello") packer.close - val up1 = MessagePack - .newDefaultUnpacker(new FileInputStream(f1)) + val up1 = MessagePack.newDefaultUnpacker(new FileInputStream(f1)) up1.unpackInt shouldBe 99 up1.unpackString shouldBe "hello" up1.hasNext shouldBe false @@ -181,24 +163,20 @@ class MessagePackerTest extends AirSpec with Benchmark { packer.packInt(99) packer.close - val up0 = MessagePack - .newDefaultUnpacker(new FileInputStream(f0)) + val up0 = MessagePack.newDefaultUnpacker(new FileInputStream(f0)) up0.unpackInt shouldBe 99 up0.hasNext shouldBe false up0.close val (f1, out1) = createTempFileWithChannel - packer - .reset(new ChannelBufferOutput(out1)) + packer.reset(new ChannelBufferOutput(out1)) packer.packInt(99) packer.flush - packer - .reset(new ChannelBufferOutput(out1)) + packer.reset(new ChannelBufferOutput(out1)) packer.packString("hello") packer.close - val up1 = MessagePack - .newDefaultUnpacker(new FileInputStream(f1)) + val up1 = MessagePack.newDefaultUnpacker(new FileInputStream(f1)) up1.unpackInt shouldBe 99 up1.unpackString shouldBe "hello" up1.hasNext shouldBe false @@ -208,32 +186,32 @@ class MessagePackerTest extends AirSpec with Benchmark { test("pack a lot of String within expected time") { val count = 20000 - def measureDuration(outputStream: java.io.OutputStream) = { + def measureDuration(outputStream: java.io.OutputStream) = val packer = MessagePack.newDefaultPacker(outputStream) var i = 0 - while (i < count) { + while i < count do packer.packString("0123456789ABCDEF") i += 1 - } packer.close - } - val t = time("packString into OutputStream", repeat = 10) { - block("byte-array-output-stream") { - measureDuration(new ByteArrayOutputStream()) - } + val t = + time("packString into OutputStream", repeat = 10) { + block("byte-array-output-stream") { + measureDuration(new ByteArrayOutputStream()) + } - block("file-output-stream") { - val (_, fileOutput) = createTempFileWithOutputStream - measureDuration(fileOutput) + block("file-output-stream") { + val (_, fileOutput) = createTempFileWithOutputStream + measureDuration(fileOutput) + } } - } - t("file-output-stream").averageWithoutMinMax < (t("byte-array-output-stream").averageWithoutMinMax * 5) shouldBe true + t("file-output-stream").averageWithoutMinMax < + (t("byte-array-output-stream").averageWithoutMinMax * 5) shouldBe true } } test("compute totalWrittenBytes") { - val out = new ByteArrayOutputStream + val out = new ByteArrayOutputStream val packerTotalWrittenBytes = withResource(MessagePack.newDefaultPacker(out)) { packer => packer @@ -254,11 +232,7 @@ class MessagePackerTest extends AirSpec with Benchmark { test("support read-only buffer") { val payload = Array[Byte](1) val out = new ByteArrayOutputStream() - val packer = MessagePack - .newDefaultPacker(out) - .packBinaryHeader(1) - .writePayload(payload) - .close() + val packer = MessagePack.newDefaultPacker(out).packBinaryHeader(1).writePayload(payload).close() } test("pack small string with STR8") { @@ -272,8 +246,7 @@ class MessagePackerTest extends AirSpec with Benchmark { } test("be able to disable STR8 for backward compatibility") { - val config = new PackerConfig() - .withStr8FormatSupport(false) + val config = new PackerConfig().withStr8FormatSupport(false) val packer = config.newBufferPacker() packer.packString("Hello. This is a string longer than 32 characters!") @@ -298,16 +271,14 @@ class MessagePackerTest extends AirSpec with Benchmark { test("write raw binary") { val packer = new MessagePack.PackerConfig().newBufferPacker() - val msg = - Array[Byte](-127, -92, 116, 121, 112, 101, -92, 112, 105, 110, 103) + val msg = Array[Byte](-127, -92, 116, 121, 112, 101, -92, 112, 105, 110, 103) packer.writePayload(msg) } test("append raw binary") { val packer = new MessagePack.PackerConfig().newBufferPacker() - val msg = - Array[Byte](-127, -92, 116, 121, 112, 101, -92, 112, 105, 110, 103) + val msg = Array[Byte](-127, -92, 116, 121, 112, 101, -92, 112, 105, 110, 103) packer.addPayload(msg) } -} +end MessagePackerTest diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala index 620e7dbe..ae25d284 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala @@ -16,41 +16,37 @@ package org.msgpack.core import org.msgpack.core.MessagePackSpec.{createMessagePackData, toHex} -import org.msgpack.core.buffer._ +import org.msgpack.core.buffer.* import org.msgpack.value.ValueType import wvlet.airspec.AirSpec import wvlet.log.LogSupport import wvlet.log.io.IOUtil.withResource -import java.io._ +import java.io.* import java.nio.ByteBuffer import java.util.Collections -import scala.jdk.CollectionConverters._ +import scala.jdk.CollectionConverters.* import scala.util.Random -object MessageUnpackerTest { - class SplitMessageBufferInput(array: Array[Array[Byte]]) extends MessageBufferInput { - var cursor = 0 - override def next(): MessageBuffer = { - if (cursor < array.length) { +object MessageUnpackerTest: + class SplitMessageBufferInput(array: Array[Array[Byte]]) extends MessageBufferInput: + var cursor = 0 + override def next(): MessageBuffer = + if cursor < array.length then val a = array(cursor) cursor += 1 MessageBuffer.wrap(a) - } else { + else null - } - } override def close(): Unit = {} - } -} -import org.msgpack.core.MessageUnpackerTest._ +import org.msgpack.core.MessageUnpackerTest.* -class MessageUnpackerTest extends AirSpec with Benchmark { +class MessageUnpackerTest extends AirSpec with Benchmark: - private val universal = MessageBuffer.allocate(0).isInstanceOf[MessageBufferU] - private def testData: Array[Byte] = { + private val universal = MessageBuffer.allocate(0).isInstanceOf[MessageBufferU] + private def testData: Array[Byte] = val out = new ByteArrayOutputStream() val packer = MessagePack.newDefaultPacker(out) @@ -68,17 +64,18 @@ class MessageUnpackerTest extends AirSpec with Benchmark { debug(s"packed: ${toHex(arr)}, size:${arr.length}") arr - } - private val intSeq = (for (i <- 0 until 100) yield Random.nextInt()).toArray[Int] + private val intSeq = + ( + for (i <- 0 until 100) + yield Random.nextInt() + ).toArray[Int] - private def testData2: Array[Byte] = { + private def testData2: Array[Byte] = val out = new ByteArrayOutputStream() val packer = MessagePack.newDefaultPacker(out); - packer - .packBoolean(true) - .packBoolean(false) + packer.packBoolean(true).packBoolean(false) intSeq.foreach(packer.packInt) packer.close() @@ -86,15 +83,15 @@ class MessageUnpackerTest extends AirSpec with Benchmark { val arr = out.toByteArray debug(s"packed: ${toHex(arr)}") arr - } - private def write(packer: MessagePacker, r: Random): Unit = { - val tpeIndex = Iterator - .continually(r.nextInt(MessageFormat.values().length)) - .find(_ != MessageFormat.NEVER_USED.ordinal()) - .get + private def write(packer: MessagePacker, r: Random): Unit = + val tpeIndex = + Iterator + .continually(r.nextInt(MessageFormat.values().length)) + .find(_ != MessageFormat.NEVER_USED.ordinal()) + .get val tpe = MessageFormat.values()(tpeIndex) - tpe.getValueType match { + tpe.getValueType match case ValueType.INTEGER => val v = r.nextInt(Int.MaxValue) @@ -124,27 +121,27 @@ class MessageUnpackerTest extends AirSpec with Benchmark { trace(s"array len: $len") packer.packArrayHeader(len) var i = 0 - while (i < len) { + while i < len do write(packer, r) i += 1 - } case ValueType.MAP => val len = r.nextInt(5) + 1 packer.packMapHeader(len) trace(s"map len: ${len}") var i = 0 - while (i < len * 2) { + while i < len * 2 do write(packer, r) i += 1 - } case _ => val v = r.nextInt(Int.MaxValue) trace(s"int: $v") packer.packInt(v) - } - } - private def testData3(N: Int): Array[Byte] = { + end match + + end write + + private def testData3(N: Int): Array[Byte] = val out = new ByteArrayOutputStream() val packer = MessagePack.newDefaultPacker(out) @@ -160,11 +157,10 @@ class MessageUnpackerTest extends AirSpec with Benchmark { trace(s"packed: ${toHex(arr)}") debug(s"size:${arr.length}") arr - } - private def readValue(unpacker: MessageUnpacker): Unit = { + private def readValue(unpacker: MessageUnpacker): Unit = val f = unpacker.getNextFormat() - f.getValueType match { + f.getValueType match case ValueType.ARRAY => val arrLen = unpacker.unpackArrayHeader() debug(s"arr size: $arrLen") @@ -180,24 +176,20 @@ class MessageUnpackerTest extends AirSpec with Benchmark { case other => unpacker.skipValue() debug(s"unknown type: $f") - } - } - private def createTempFile: File = { + private def createTempFile: File = val f = File.createTempFile("msgpackTest", "msgpack") f.deleteOnExit val p = MessagePack.newDefaultPacker(new FileOutputStream(f)) p.packInt(99) p.close f - } - private def checkFile(u: MessageUnpacker): Boolean = { + private def checkFile(u: MessageUnpacker): Boolean = u.unpackInt shouldBe 99 u.hasNext shouldBe false - } - private def unpackers(data: Array[Byte]): Seq[MessageUnpacker] = { + private def unpackers(data: Array[Byte]): Seq[MessageUnpacker] = val bb = ByteBuffer.allocate(data.length) val db = ByteBuffer.allocateDirect(data.length) bb.put(data).flip() @@ -205,20 +197,21 @@ class MessageUnpackerTest extends AirSpec with Benchmark { val builder = Seq.newBuilder[MessageUnpacker] builder += MessagePack.newDefaultUnpacker(data) builder += MessagePack.newDefaultUnpacker(bb) - if (!universal) { + if !universal then builder += MessagePack.newDefaultUnpacker(db) - } builder.result() - } - private def unpackerCollectionWithVariousBuffers(data: Array[Byte], chunkSize: Int): Seq[MessageUnpacker] = { + private def unpackerCollectionWithVariousBuffers( + data: Array[Byte], + chunkSize: Int + ): Seq[MessageUnpacker] = val seqBytes = Seq.newBuilder[MessageBufferInput] val seqByteBuffers = Seq.newBuilder[MessageBufferInput] val seqDirectBuffers = Seq.newBuilder[MessageBufferInput] var left = data.length var position = 0 - while (left > 0) { + while left > 0 do val length = Math.min(chunkSize, left) seqBytes += new ArrayBufferInput(data, position, length) val bb = ByteBuffer.allocate(length) @@ -229,52 +222,56 @@ class MessageUnpackerTest extends AirSpec with Benchmark { seqDirectBuffers += new ByteBufferInput(db) left -= length position += length - } val builder = Seq.newBuilder[MessageUnpacker] - builder += MessagePack.newDefaultUnpacker(new SequenceMessageBufferInput(Collections.enumeration(seqBytes.result().asJava))) - builder += MessagePack.newDefaultUnpacker(new SequenceMessageBufferInput(Collections.enumeration(seqByteBuffers.result().asJava))) - if (!universal) { - builder += MessagePack.newDefaultUnpacker(new SequenceMessageBufferInput(Collections.enumeration(seqDirectBuffers.result().asJava))) - } + builder += + MessagePack.newDefaultUnpacker( + new SequenceMessageBufferInput(Collections.enumeration(seqBytes.result().asJava)) + ) + builder += + MessagePack.newDefaultUnpacker( + new SequenceMessageBufferInput(Collections.enumeration(seqByteBuffers.result().asJava)) + ) + if !universal then + builder += + MessagePack.newDefaultUnpacker( + new SequenceMessageBufferInput(Collections.enumeration(seqDirectBuffers.result().asJava)) + ) builder.result() - } + + end unpackerCollectionWithVariousBuffers test("MessageUnpacker") { test("parse message packed data") { val arr = testData - for (unpacker <- unpackers(arr)) { + for unpacker <- unpackers(arr) do var count = 0 - while (unpacker.hasNext) { + while unpacker.hasNext do count += 1 readValue(unpacker) - } count shouldBe 6 unpacker.getTotalReadBytes shouldBe arr.length unpacker.close() unpacker.getTotalReadBytes shouldBe arr.length - } } test("skip reading values") { - for (unpacker <- unpackers(testData)) { + for unpacker <- unpackers(testData) do var skipCount = 0 - while (unpacker.hasNext) { + while unpacker.hasNext do unpacker.skipValue() skipCount += 1 - } skipCount shouldBe 2 unpacker.getTotalReadBytes shouldBe testData.length unpacker.close() unpacker.getTotalReadBytes shouldBe testData.length - } } test("compare skip performance") { @@ -283,23 +280,20 @@ class MessageUnpackerTest extends AirSpec with Benchmark { time("skip performance", repeat = 100) { block("switch") { - for (unpacker <- unpackers(data)) { + for unpacker <- unpackers(data) do var skipCount = 0 - while (unpacker.hasNext) { + while unpacker.hasNext do unpacker.skipValue() skipCount += 1 - } skipCount shouldBe N - } } } time("bulk skip performance", repeat = 100) { block("switch") { - for (unpacker <- unpackers(data)) { + for unpacker <- unpackers(data) do unpacker.skipValue(N) unpacker.hasNext shouldBe false - } } } @@ -308,12 +302,12 @@ class MessageUnpackerTest extends AirSpec with Benchmark { test("parse int data") { debug(intSeq.mkString(", ")) - for (unpacker <- unpackers(testData2)) { + for unpacker <- unpackers(testData2) do val ib = Seq.newBuilder[Int] - while (unpacker.hasNext) { + while unpacker.hasNext do val f = unpacker.getNextFormat - f.getValueType match { + f.getValueType match case ValueType.INTEGER => val i = unpacker.unpackInt() trace(f"read int: $i%,d") @@ -323,54 +317,48 @@ class MessageUnpackerTest extends AirSpec with Benchmark { trace(s"read boolean: $b") case other => unpacker.skipValue() - } - } ib.result() shouldBe intSeq.toSeq unpacker.getTotalReadBytes shouldBe testData2.length unpacker.close() unpacker.getTotalReadBytes shouldBe testData2.length - } } test("read data at the buffer boundary") { - trait SplitTest extends LogSupport { + trait SplitTest extends LogSupport: val data: Array[Byte] - def run: Unit = { - for (unpacker <- unpackers(data)) { - val numElems = { + def run: Unit = + for unpacker <- unpackers(data) do + val numElems = var c = 0 - while (unpacker.hasNext) { + while unpacker.hasNext do readValue(unpacker) c += 1 - } c - } - for (splitPoint <- 1 until data.length - 1) { + for splitPoint <- 1 until data.length - 1 do debug(s"split at $splitPoint") val (h, t) = data.splitAt(splitPoint) val bin = new SplitMessageBufferInput(Array(h, t)) val unpacker = MessagePack.newDefaultUnpacker(bin) var count = 0 - while (unpacker.hasNext) { + while unpacker.hasNext do count += 1 val f = unpacker.getNextFormat readValue(unpacker) - } count shouldBe numElems unpacker.getTotalReadBytes shouldBe data.length unpacker.close() unpacker.getTotalReadBytes shouldBe data.length - } - } - } - } - new SplitTest { val data = testData }.run - new SplitTest { val data = testData3(30) }.run + new SplitTest: + val data = testData + .run + new SplitTest: + val data = testData3(30) + .run } test("read integer at MessageBuffer boundaries") { @@ -382,18 +370,21 @@ class MessageUnpackerTest extends AirSpec with Benchmark { val data = packer.toByteArray // Boundary test - withResource(MessagePack.newDefaultUnpacker(new InputStreamBufferInput(new ByteArrayInputStream(data), 8192))) { unpacker => + withResource( + MessagePack.newDefaultUnpacker( + new InputStreamBufferInput(new ByteArrayInputStream(data), 8192) + ) + ) { unpacker => (0 until 1170).foreach { i => unpacker.unpackLong() shouldBe 0x0011223344556677L } } // Boundary test for sequences of ByteBuffer, DirectByteBuffer backed MessageInput. - for (unpacker <- unpackerCollectionWithVariousBuffers(data, 32)) { + for unpacker <- unpackerCollectionWithVariousBuffers(data, 32) do (0 until 1170).foreach { i => unpacker.unpackLong() shouldBe 0x0011223344556677L } - } } test("read string at MessageBuffer boundaries") { @@ -405,36 +396,34 @@ class MessageUnpackerTest extends AirSpec with Benchmark { val data = packer.toByteArray // Boundary test - withResource(MessagePack.newDefaultUnpacker(new InputStreamBufferInput(new ByteArrayInputStream(data), 8192))) { unpacker => + withResource( + MessagePack.newDefaultUnpacker( + new InputStreamBufferInput(new ByteArrayInputStream(data), 8192) + ) + ) { unpacker => (0 until 1170).foreach { i => unpacker.unpackString() shouldBe "hello world" } } // Boundary test for sequences of ByteBuffer, DirectByteBuffer backed MessageInput. - for (unpacker <- unpackerCollectionWithVariousBuffers(data, 32)) { + for unpacker <- unpackerCollectionWithVariousBuffers(data, 32) do (0 until 1170).foreach { i => unpacker.unpackString() shouldBe "hello world" } - } } test("be faster than msgpack-v6 skip") { - trait Fixture { + trait Fixture: val unpacker: MessageUnpacker - def run: Unit = { + def run: Unit = var count = 0 - try { - while (unpacker.hasNext) { + try + while unpacker.hasNext do unpacker.skipValue() count += 1 - } - } finally { - unpacker.close() - } - } - } + finally unpacker.close() val data = testData3(10000) val N = 100 @@ -443,64 +432,69 @@ class MessageUnpackerTest extends AirSpec with Benchmark { val db = ByteBuffer.allocateDirect(data.length) db.put(data).flip() - val t = time("skip performance", repeat = N) { - block("v6") { - val v6 = new org.msgpack.MessagePack() - val unpacker = new org.msgpack.unpacker.MessagePackUnpacker(v6, new ByteArrayInputStream(data)) - var count = 0 - try { - while (true) { - unpacker.skip() - count += 1 - } - } catch { - case e: EOFException => - } finally unpacker.close() - } + val t = + time("skip performance", repeat = N) { + block("v6") { + val v6 = new org.msgpack.MessagePack() + val unpacker = + new org.msgpack.unpacker.MessagePackUnpacker(v6, new ByteArrayInputStream(data)) + var count = 0 + try + while true do + unpacker.skip() + count += 1 + catch + case e: EOFException => + finally + unpacker.close() + } - block("v7-array") { - new Fixture { - override val unpacker = MessagePack.newDefaultUnpacker(data) - }.run - } + block("v7-array") { + new Fixture: + override val unpacker = MessagePack.newDefaultUnpacker(data) + .run + } - block("v7-array-buffer") { - new Fixture { - override val unpacker = MessagePack.newDefaultUnpacker(bb) - }.run - } - if (!universal) block("v7-direct-buffer") { - new Fixture { - override val unpacker = MessagePack.newDefaultUnpacker(db) - }.run + block("v7-array-buffer") { + new Fixture: + override val unpacker = MessagePack.newDefaultUnpacker(bb) + .run + } + if !universal then + block("v7-direct-buffer") { + new Fixture: + override val unpacker = MessagePack.newDefaultUnpacker(db) + .run + } } - } t("v7-array").averageWithoutMinMax <= t("v6").averageWithoutMinMax shouldBe true t("v7-array-buffer").averageWithoutMinMax <= t("v6").averageWithoutMinMax shouldBe true - if (!universal) { + if !universal then t("v7-direct-buffer").averageWithoutMinMax <= t("v6").averageWithoutMinMax shouldBe true - } } - import org.msgpack.`type`.{ValueType => ValueTypeV6} + import org.msgpack.`type`.ValueType as ValueTypeV6 test("be faster than msgpack-v6 read value") { - def readValueV6(unpacker: org.msgpack.unpacker.MessagePackUnpacker): Unit = { + def readValueV6(unpacker: org.msgpack.unpacker.MessagePackUnpacker): Unit = val vt = unpacker.getNextType() - vt match { + vt match case ValueTypeV6.ARRAY => val len = unpacker.readArrayBegin() var i = 0 - while (i < len) { readValueV6(unpacker); i += 1 } + while i < len do + readValueV6(unpacker); + i += 1 unpacker.readArrayEnd() case ValueTypeV6.MAP => val len = unpacker.readMapBegin() var i = 0 - while (i < len) { - readValueV6(unpacker); readValueV6(unpacker); i += 1 - } + while i < len do + readValueV6(unpacker); + readValueV6(unpacker); + i += 1 unpacker.readMapEnd() case ValueTypeV6.NIL => unpacker.readNil() @@ -514,23 +508,27 @@ class MessageUnpackerTest extends AirSpec with Benchmark { unpacker.readByteArray() case _ => unpacker.skip() - } - } + end readValueV6 val buf = new Array[Byte](8192) - def readValue(unpacker: MessageUnpacker): Unit = { + def readValue(unpacker: MessageUnpacker): Unit = val f = unpacker.getNextFormat val vt = f.getValueType - vt match { + vt match case ValueType.ARRAY => val len = unpacker.unpackArrayHeader() var i = 0 - while (i < len) { readValue(unpacker); i += 1 } + while i < len do + readValue(unpacker); + i += 1 case ValueType.MAP => val len = unpacker.unpackMapHeader() var i = 0 - while (i < len) { readValue(unpacker); readValue(unpacker); i += 1 } + while i < len do + readValue(unpacker); + readValue(unpacker); + i += 1 case ValueType.NIL => unpacker.unpackNil() case ValueType.INTEGER => @@ -547,20 +545,17 @@ class MessageUnpackerTest extends AirSpec with Benchmark { unpacker.readPayload(buf, 0, len) case _ => unpacker.skipValue() - } - } - trait Fixture { + end match + end readValue + trait Fixture: val unpacker: MessageUnpacker - def run: Unit = { + def run: Unit = var count = 0 - try { - while (unpacker.hasNext) { + try + while unpacker.hasNext do readValue(unpacker) count += 1 - } - } finally unpacker.close() - } - } + finally unpacker.close() val data = testData3(10000) val N = 100 @@ -569,49 +564,55 @@ class MessageUnpackerTest extends AirSpec with Benchmark { val db = ByteBuffer.allocateDirect(data.length) db.put(data).flip() - val t = time("unpack performance", repeat = N) { - block("v6") { - val v6 = new org.msgpack.MessagePack() - val unpacker = new org.msgpack.unpacker.MessagePackUnpacker(v6, new ByteArrayInputStream(data)) - var count = 0 - try { - while (true) { - readValueV6(unpacker) - count += 1 - } - } catch { - case e: EOFException => - } finally unpacker.close() - } + val t = + time("unpack performance", repeat = N) { + block("v6") { + val v6 = new org.msgpack.MessagePack() + val unpacker = + new org.msgpack.unpacker.MessagePackUnpacker(v6, new ByteArrayInputStream(data)) + var count = 0 + try + while true do + readValueV6(unpacker) + count += 1 + catch + case e: EOFException => + finally + unpacker.close() + } - block("v7-array") { - new Fixture { - override val unpacker = MessagePack.newDefaultUnpacker(data) - }.run - } + block("v7-array") { + new Fixture: + override val unpacker = MessagePack.newDefaultUnpacker(data) + .run + } - block("v7-array-buffer") { - new Fixture { - override val unpacker = MessagePack.newDefaultUnpacker(bb) - }.run - } + block("v7-array-buffer") { + new Fixture: + override val unpacker = MessagePack.newDefaultUnpacker(bb) + .run + } - if (!universal) block("v7-direct-buffer") { - new Fixture { - override val unpacker = MessagePack.newDefaultUnpacker(db) - }.run + if !universal then + block("v7-direct-buffer") { + new Fixture: + override val unpacker = MessagePack.newDefaultUnpacker(db) + .run + } } - } - if (t("v7-array").averageWithoutMinMax > t("v6").averageWithoutMinMax) { - warn(s"v7-array ${t("v7-array").averageWithoutMinMax} is slower than v6 ${t("v6").averageWithoutMinMax}") - } - if (t("v7-array-buffer").averageWithoutMinMax > t("v6").averageWithoutMinMax) { - warn(s"v7-array-buffer ${t("v7-array-buffer").averageWithoutMinMax} is slower than v6 ${t("v6").averageWithoutMinMax}") - } - if (!universal) { + if t("v7-array").averageWithoutMinMax > t("v6").averageWithoutMinMax then + warn( + s"v7-array ${t("v7-array").averageWithoutMinMax} is slower than v6 ${t("v6") + .averageWithoutMinMax}" + ) + if t("v7-array-buffer").averageWithoutMinMax > t("v6").averageWithoutMinMax then + warn( + s"v7-array-buffer ${t("v7-array-buffer").averageWithoutMinMax} is slower than v6 ${t("v6") + .averageWithoutMinMax}" + ) + if !universal then t("v7-direct-buffer").averageWithoutMinMax <= t("v6").averageWithoutMinMax shouldBe true - } } test("be faster for reading binary than v6") { @@ -626,31 +627,26 @@ class MessageUnpackerTest extends AirSpec with Benchmark { } packer.close() - trait Fixture { + trait Fixture: val unpacker: MessageUnpacker val loop: Int - def run: Unit = { + def run: Unit = var i = 0 - try { - while (i < loop) { + try + while i < loop do val len = unpacker.unpackBinaryHeader() val out = new Array[Byte](len) unpacker.readPayload(out, 0, len) i += 1 - } - } finally unpacker.close() - } - def runRef: Unit = { + finally unpacker.close() + def runRef: Unit = var i = 0 - try { - while (i < loop) { + try + while i < loop do val len = unpacker.unpackBinaryHeader() val out = unpacker.readPayloadAsReference(len) i += 1 - } - } finally unpacker.close() - } - } + finally unpacker.close() val b = bos.toByteArray val bb = ByteBuffer.allocate(b.length) bb.put(b).flip() @@ -659,66 +655,67 @@ class MessageUnpackerTest extends AirSpec with Benchmark { time("unpackBinary", repeat = 100) { block("v6") { - val v6 = new org.msgpack.MessagePack() - val unpacker = new org.msgpack.unpacker.MessagePackUnpacker(v6, new ByteArrayInputStream(b)) - var i = 0 - while (i < R) { + val v6 = new org.msgpack.MessagePack() + val unpacker = + new org.msgpack.unpacker.MessagePackUnpacker(v6, new ByteArrayInputStream(b)) + var i = 0 + while i < R do val out = unpacker.readByteArray() i += 1 - } unpacker.close() } block("v7-array") { - new Fixture { + new Fixture: override val unpacker = MessagePack.newDefaultUnpacker(b) override val loop = R - }.run + .run } block("v7-array-buffer") { - new Fixture { + new Fixture: override val unpacker = MessagePack.newDefaultUnpacker(bb) override val loop = R - }.run + .run } - if (!universal) block("v7-direct-buffer") { - new Fixture { - override val unpacker = MessagePack.newDefaultUnpacker(db) - override val loop = R - }.run - } + if !universal then + block("v7-direct-buffer") { + new Fixture: + override val unpacker = MessagePack.newDefaultUnpacker(db) + override val loop = R + .run + } block("v7-ref-array") { - new Fixture { + new Fixture: override val unpacker = MessagePack.newDefaultUnpacker(b) override val loop = R - }.runRef + .runRef } block("v7-ref-array-buffer") { - new Fixture { + new Fixture: override val unpacker = MessagePack.newDefaultUnpacker(bb) override val loop = R - }.runRef + .runRef } - if (!universal) block("v7-ref-direct-buffer") { - new Fixture { - override val unpacker = MessagePack.newDefaultUnpacker(db) - override val loop = R - }.runRef - } + if !universal then + block("v7-ref-direct-buffer") { + new Fixture: + override val unpacker = MessagePack.newDefaultUnpacker(db) + override val loop = R + .runRef + } } } test("read payload as a reference") { - val dataSizes = - Seq(0, 1, 5, 8, 16, 32, 128, 256, 1024, 2000, 10000, 100000) + val dataSizes = Seq(0, 1, 5, 8, 16, 32, 128, 256, 1024, 2000, 10000, 100000) - for (s <- dataSizes) { + for s <- dataSizes do test(f"data size is $s%,d") { val data = new Array[Byte](s) Random.nextBytes(data) @@ -728,7 +725,7 @@ class MessageUnpackerTest extends AirSpec with Benchmark { packer.writePayload(data) packer.close() - for (unpacker <- unpackers(b.toByteArray)) { + for unpacker <- unpackers(b.toByteArray) do val len = unpacker.unpackBinaryHeader() len shouldBe s val ref = unpacker.readPayloadAsReference(len) @@ -738,21 +735,18 @@ class MessageUnpackerTest extends AirSpec with Benchmark { ref.getBytes(0, stored, 0, len) stored shouldBe data - } } - } } test("reset the internal states") { val data = intSeq val b = createMessagePackData(packer => data foreach packer.packInt) - for (unpacker <- unpackers(b)) { + for unpacker <- unpackers(b) do val unpacked = Array.newBuilder[Int] - while (unpacker.hasNext) { + while unpacker.hasNext do unpacked += unpacker.unpackInt() - } unpacker.close unpacked.result() shouldBe data @@ -761,9 +755,8 @@ class MessageUnpackerTest extends AirSpec with Benchmark { val bi = new ArrayBufferInput(b2) unpacker.reset(bi) val unpacked2 = Array.newBuilder[Int] - while (unpacker.hasNext) { + while unpacker.hasNext do unpacked2 += unpacker.unpackInt() - } unpacker.close unpacked2.result() shouldBe data2 @@ -771,12 +764,10 @@ class MessageUnpackerTest extends AirSpec with Benchmark { bi.reset(b2) unpacker.reset(bi) val unpacked3 = Array.newBuilder[Int] - while (unpacker.hasNext) { + while unpacker.hasNext do unpacked3 += unpacker.unpackInt() - } unpacker.close unpacked3.result() shouldBe data2 - } } @@ -790,42 +781,40 @@ class MessageUnpackerTest extends AirSpec with Benchmark { val mb = MessageBuffer.wrap(arr) val N = 1000 - val t = time("unpacker", repeat = 10) { - block("no-buffer-reset") { - withResource(MessagePack.newDefaultUnpacker(arr)) { unpacker => - for (i <- 0 until N) { - val buf = new ArrayBufferInput(arr) - unpacker.reset(buf) - unpacker.unpackInt - unpacker.close + val t = + time("unpacker", repeat = 10) { + block("no-buffer-reset") { + withResource(MessagePack.newDefaultUnpacker(arr)) { unpacker => + for i <- 0 until N do + val buf = new ArrayBufferInput(arr) + unpacker.reset(buf) + unpacker.unpackInt + unpacker.close } } - } - block("reuse-array-input") { - withResource(MessagePack.newDefaultUnpacker(arr)) { unpacker => - val buf = new ArrayBufferInput(arr) - for (i <- 0 until N) { - buf.reset(arr) - unpacker.reset(buf) - unpacker.unpackInt - unpacker.close + block("reuse-array-input") { + withResource(MessagePack.newDefaultUnpacker(arr)) { unpacker => + val buf = new ArrayBufferInput(arr) + for i <- 0 until N do + buf.reset(arr) + unpacker.reset(buf) + unpacker.unpackInt + unpacker.close } } - } - block("reuse-message-buffer") { - withResource(MessagePack.newDefaultUnpacker(arr)) { unpacker => - val buf = new ArrayBufferInput(arr) - for (i <- 0 until N) { - buf.reset(mb) - unpacker.reset(buf) - unpacker.unpackInt - unpacker.close + block("reuse-message-buffer") { + withResource(MessagePack.newDefaultUnpacker(arr)) { unpacker => + val buf = new ArrayBufferInput(arr) + for i <- 0 until N do + buf.reset(mb) + unpacker.reset(buf) + unpacker.unpackInt + unpacker.close } } } - } // This performance comparison is too close, so we disabled it // t("reuse-message-buffer").averageWithoutMinMax should be <= t("no-buffer-reset").averageWithoutMinMax @@ -857,24 +846,20 @@ class MessageUnpackerTest extends AirSpec with Benchmark { } test("unpack large string data") { - def createLargeData(stringLength: Int): Array[Byte] = { + def createLargeData(stringLength: Int): Array[Byte] = val out = new ByteArrayOutputStream() val packer = MessagePack.newDefaultPacker(out) - packer - .packArrayHeader(2) - .packString("l" * stringLength) - .packInt(1) + packer.packArrayHeader(2).packString("l" * stringLength).packInt(1) packer.close() out.toByteArray - } Seq(8191, 8192, 8193, 16383, 16384, 16385).foreach { n => val arr = createLargeData(n) - for (unpacker <- unpackers(arr)) { + for unpacker <- unpackers(arr) do unpacker.unpackArrayHeader shouldBe 2 unpacker.unpackString.length shouldBe n @@ -884,12 +869,11 @@ class MessageUnpackerTest extends AirSpec with Benchmark { unpacker.close() unpacker.getTotalReadBytes shouldBe arr.length - } } } test("unpack string crossing end of buffer") { - def check(expected: String, strLen: Int) = { + def check(expected: String, strLen: Int) = val bytes = new Array[Byte](strLen) val out = new ByteArrayOutputStream @@ -899,52 +883,58 @@ class MessageUnpackerTest extends AirSpec with Benchmark { packer.packString(expected) packer.close - val unpacker = MessagePack.newDefaultUnpacker(new InputStreamBufferInput(new ByteArrayInputStream(out.toByteArray))) - val len = unpacker.unpackBinaryHeader + val unpacker = MessagePack.newDefaultUnpacker( + new InputStreamBufferInput(new ByteArrayInputStream(out.toByteArray)) + ) + val len = unpacker.unpackBinaryHeader unpacker.readPayload(len) val got = unpacker.unpackString unpacker.close got shouldBe expected - } - Seq("\u3042", "a\u3042", "\u3042a", "\u3042\u3044\u3046\u3048\u304A\u304B\u304D\u304F\u3051\u3053\u3055\u3057\u3059\u305B\u305D") - .foreach { s => - Seq(8185, 8186, 8187, 8188, 16377, 16378, 16379, 16380).foreach { n => - check(s, n) - } + Seq( + "\u3042", + "a\u3042", + "\u3042a", + "\u3042\u3044\u3046\u3048\u304A\u304B\u304D\u304F\u3051\u3053\u3055\u3057\u3059\u305B\u305D" + ).foreach { s => + Seq(8185, 8186, 8187, 8188, 16377, 16378, 16379, 16380).foreach { n => + check(s, n) } + } } - def readTest(input: MessageBufferInput): Unit = { + def readTest(input: MessageBufferInput): Unit = withResource(MessagePack.newDefaultUnpacker(input)) { unpacker => - while (unpacker.hasNext) { + while unpacker.hasNext do unpacker.unpackValue() - } } - } test("read value length at buffer boundary") { - val input = new SplitMessageBufferInput( - Array( - Array[Byte](MessagePack.Code.STR16), - Array[Byte](0x00), - Array[Byte](0x05), // STR16 length at the boundary - "hello".getBytes(MessagePack.UTF8) + val input = + new SplitMessageBufferInput( + Array( + Array[Byte](MessagePack.Code.STR16), + Array[Byte](0x00), + Array[Byte](0x05), // STR16 length at the boundary + "hello".getBytes(MessagePack.UTF8) + ) ) - ) readTest(input) - val input2 = new SplitMessageBufferInput( - Array( - Array[Byte](MessagePack.Code.STR32), - Array[Byte](0x00), - Array[Byte](0x00, 0x00), - Array[Byte](0x05), // STR32 length at the boundary - "hello".getBytes(MessagePack.UTF8) + val input2 = + new SplitMessageBufferInput( + Array( + Array[Byte](MessagePack.Code.STR32), + Array[Byte](0x00), + Array[Byte](0x00, 0x00), + Array[Byte](0x05), // STR32 length at the boundary + "hello".getBytes(MessagePack.UTF8) + ) ) - ) readTest(input2) } } -} + +end MessageUnpackerTest diff --git a/msgpack-core/src/test/scala/org/msgpack/core/StringLimitTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/StringLimitTest.scala index 96319a7f..c54ce632 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/StringLimitTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/StringLimitTest.scala @@ -4,7 +4,7 @@ import org.msgpack.core.MessagePack.UnpackerConfig import org.msgpack.value.Variable import wvlet.airspec.AirSpec -class StringLimitTest extends AirSpec { +class StringLimitTest extends AirSpec: test("throws an exception when the string size exceeds a limit") { val customLimit = 100 @@ -34,4 +34,5 @@ class StringLimitTest extends AirSpec { } } } -} + +end StringLimitTest diff --git a/msgpack-core/src/test/scala/org/msgpack/core/buffer/ByteStringTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/buffer/ByteStringTest.scala index 42872fc4..06d363fd 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/buffer/ByteStringTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/buffer/ByteStringTest.scala @@ -20,28 +20,26 @@ import org.msgpack.core.MessagePack import org.msgpack.core.MessagePackSpec.createMessagePackData import wvlet.airspec.AirSpec -class ByteStringTest extends AirSpec { +class ByteStringTest extends AirSpec: private val unpackedString = "foo" private val byteString = ByteString(createMessagePackData(_.packString(unpackedString))) - private def unpackString(messageBuffer: MessageBuffer) = { - val input = new MessageBufferInput { + private def unpackString(messageBuffer: MessageBuffer) = + val input = + new MessageBufferInput: - private var isRead = false + private var isRead = false - override def next(): MessageBuffer = - if (isRead) { - null - } else { - isRead = true - messageBuffer - } - override def close(): Unit = {} - } + override def next(): MessageBuffer = + if isRead then + null + else + isRead = true + messageBuffer + override def close(): Unit = {} MessagePack.newDefaultUnpacker(input).unpackString() - } test("Unpacking a ByteString's ByteBuffer") { test("fail with a regular MessageBuffer") { @@ -53,4 +51,5 @@ class ByteStringTest extends AirSpec { } } } -} + +end ByteStringTest diff --git a/msgpack-core/src/test/scala/org/msgpack/core/buffer/DirectBufferAccessTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/buffer/DirectBufferAccessTest.scala index 40f4c770..5bb4b49d 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/buffer/DirectBufferAccessTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/buffer/DirectBufferAccessTest.scala @@ -19,11 +19,10 @@ import wvlet.airspec.AirSpec import java.nio.ByteBuffer -class DirectBufferAccessTest extends AirSpec { +class DirectBufferAccessTest extends AirSpec: test("instantiate DirectBufferAccess") { val bb = ByteBuffer.allocateDirect(1) val addr = DirectBufferAccess.getAddress(bb) } -} diff --git a/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferInputTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferInputTest.scala index a43704fb..5e6c1f96 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferInputTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferInputTest.scala @@ -19,7 +19,7 @@ import org.msgpack.core.MessagePack import wvlet.airspec.AirSpec import wvlet.log.io.IOUtil.withResource -import java.io._ +import java.io.* import java.net.InetSocketAddress import java.nio.ByteBuffer import java.nio.channels.{ServerSocketChannel, SocketChannel} @@ -27,63 +27,49 @@ import java.util.concurrent.{Callable, Executors, TimeUnit} import java.util.zip.{GZIPInputStream, GZIPOutputStream} import scala.util.Random -class MessageBufferInputTest extends AirSpec { +class MessageBufferInputTest extends AirSpec: - private val targetInputSize = - Seq(0, 10, 500, 1000, 2000, 4000, 8000, 10000, 30000, 50000, 100000) + private val targetInputSize = Seq(0, 10, 500, 1000, 2000, 4000, 8000, 10000, 30000, 50000, 100000) - private def testData(size: Int): Array[Byte] = { + private def testData(size: Int): Array[Byte] = // debug(s"test data size: ${size}") val b = new Array[Byte](size) Random.nextBytes(b) b - } - private def testDataSet: Seq[Array[Byte]] = { - targetInputSize.map(testData) - } + private def testDataSet: Seq[Array[Byte]] = targetInputSize.map(testData) - private def runTest(factory: Array[Byte] => MessageBufferInput): Unit = { - for (b <- testDataSet) { + private def runTest(factory: Array[Byte] => MessageBufferInput): Unit = + for b <- testDataSet do checkInputData(b, factory(b)) - } - } - implicit class InputData(b: Array[Byte]) { - def compress = { + implicit class InputData(b: Array[Byte]): + def compress = val compressed = new ByteArrayOutputStream() val out = new GZIPOutputStream(compressed) out.write(b) out.close() compressed.toByteArray - } - def toByteBuffer = { - ByteBuffer.wrap(b) - } + def toByteBuffer = ByteBuffer.wrap(b) - def saveToTmpFile: File = { - val tmp = File - .createTempFile("testbuf", ".dat", new File("target")) + def saveToTmpFile: File = + val tmp = File.createTempFile("testbuf", ".dat", new File("target")) tmp.getParentFile.mkdirs() tmp.deleteOnExit() withResource(new FileOutputStream(tmp)) { out => out.write(b) } tmp - } - } - private def checkInputData(inputData: Array[Byte], in: MessageBufferInput): Unit = { + private def checkInputData(inputData: Array[Byte], in: MessageBufferInput): Unit = test(s"When input data size = ${inputData.length}") { var cursor = 0 - for (m <- Iterator.continually(in.next).takeWhile(_ != null)) { + for m <- Iterator.continually(in.next).takeWhile(_ != null) do m.toByteArray() shouldBe inputData.slice(cursor, cursor + m.size()) cursor += m.size() - } cursor shouldBe inputData.length } - } test("MessageBufferInput") { test("support byte arrays") { @@ -95,46 +81,40 @@ class MessageBufferInputTest extends AirSpec { } test("support InputStreams") { - runTest(b => new InputStreamBufferInput(new GZIPInputStream(new ByteArrayInputStream(b.compress)))) + runTest(b => + new InputStreamBufferInput(new GZIPInputStream(new ByteArrayInputStream(b.compress))) + ) } test("support file input channel") { runTest { b => val tmp = b.saveToTmpFile - try { - InputStreamBufferInput - .newBufferInput(new FileInputStream(tmp)) - } finally { - tmp.delete() - } + try InputStreamBufferInput.newBufferInput(new FileInputStream(tmp)) + finally tmp.delete() } } } - private def createTempFile = { + private def createTempFile = val f = File.createTempFile("msgpackTest", "msgpack") f.deleteOnExit f - } - private def createTempFileWithInputStream = { + private def createTempFileWithInputStream = val f = createTempFile val out = new FileOutputStream(f) MessagePack.newDefaultPacker(out).packInt(42).close val in = new FileInputStream(f) (f, in) - } - private def createTempFileWithChannel = { + private def createTempFileWithChannel = val (f, in) = createTempFileWithInputStream val ch = in.getChannel (f, ch) - } - private def readInt(buf: MessageBufferInput): Int = { + private def readInt(buf: MessageBufferInput): Int = val unpacker = MessagePack.newDefaultUnpacker(buf) unpacker.unpackInt - } test("InputStreamBufferInput") { test("reset buffer") { @@ -186,42 +166,42 @@ class MessageBufferInputTest extends AirSpec { } test("unpack without blocking") { - val server = - ServerSocketChannel.open.bind(new InetSocketAddress("localhost", 0)) + val server = ServerSocketChannel.open.bind(new InetSocketAddress("localhost", 0)) val executorService = Executors.newCachedThreadPool - try { - executorService.execute(new Runnable { - override def run: Unit = { - val server_ch = server.accept - val packer = MessagePack.newDefaultPacker(server_ch) - packer.packString("0123456789") - packer.flush - // Keep the connection open - while (!executorService.isShutdown) { - TimeUnit.SECONDS.sleep(1) - } - packer.close - } - }) - - val future = executorService.submit(new Callable[String] { - override def call: String = { - val conn_ch = SocketChannel.open(new InetSocketAddress("localhost", server.socket.getLocalPort)) - val unpacker = MessagePack.newDefaultUnpacker(conn_ch) - val s = unpacker.unpackString - unpacker.close - s - } - }) + try + executorService.execute( + new Runnable: + override def run: Unit = + val server_ch = server.accept + val packer = MessagePack.newDefaultPacker(server_ch) + packer.packString("0123456789") + packer.flush + // Keep the connection open + while !executorService.isShutdown do + TimeUnit.SECONDS.sleep(1) + packer.close + ) + + val future = executorService.submit( + new Callable[String]: + override def call: String = + val conn_ch = SocketChannel.open( + new InetSocketAddress("localhost", server.socket.getLocalPort) + ) + val unpacker = MessagePack.newDefaultUnpacker(conn_ch) + val s = unpacker.unpackString + unpacker.close + s + ) future.get(5, TimeUnit.SECONDS) shouldBe "0123456789" - } finally { + finally executorService.shutdown - if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) { + if !executorService.awaitTermination(5, TimeUnit.SECONDS) then executorService.shutdownNow - } - } + end try } } -} + +end MessageBufferInputTest diff --git a/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferOutputTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferOutputTest.scala index ea9cde57..5f6e9b7a 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferOutputTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferOutputTest.scala @@ -17,34 +17,30 @@ package org.msgpack.core.buffer import wvlet.airspec.AirSpec -import java.io._ +import java.io.* -class MessageBufferOutputTest extends AirSpec { +class MessageBufferOutputTest extends AirSpec: - private def createTempFile = { + private def createTempFile = val f = File.createTempFile("msgpackTest", "msgpack") f.deleteOnExit f - } - private def createTempFileWithOutputStream = { + private def createTempFileWithOutputStream = val f = createTempFile val out = new FileOutputStream(f) (f, out) - } - private def createTempFileWithChannel = { + private def createTempFileWithChannel = val (f, out) = createTempFileWithOutputStream val ch = out.getChannel (f, ch) - } - private def writeIntToBuf(buf: MessageBufferOutput) = { + private def writeIntToBuf(buf: MessageBufferOutput) = val mb0 = buf.next(8) mb0.putInt(0, 42) buf.writeBuffer(4) buf.close - } test("OutputStreamBufferOutput") { test("reset buffer") { @@ -73,4 +69,5 @@ class MessageBufferOutputTest extends AirSpec { f1.length.toInt > 0 shouldBe true } } -} + +end MessageBufferOutputTest diff --git a/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferTest.scala index 03e93b89..36940473 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferTest.scala @@ -21,9 +21,10 @@ import wvlet.airspec.AirSpec import java.nio.ByteBuffer import scala.util.Random -/** Created on 2014/05/01. +/** + * Created on 2014/05/01. */ -class MessageBufferTest extends AirSpec with Benchmark { +class MessageBufferTest extends AirSpec with Benchmark: private val universal = MessageBuffer.allocate(0).isInstanceOf[MessageBufferU] @@ -54,97 +55,87 @@ class MessageBufferTest extends AirSpec with Benchmark { val ub = MessageBuffer.allocate(M) val ud = - if (universal) MessageBuffer.wrap(ByteBuffer.allocate(M)) - else MessageBuffer.wrap(ByteBuffer.allocateDirect(M)) + if universal then + MessageBuffer.wrap(ByteBuffer.allocate(M)) + else + MessageBuffer.wrap(ByteBuffer.allocateDirect(M)) val hb = ByteBuffer.allocate(M) val db = ByteBuffer.allocateDirect(M) - def bench(f: Int => Unit): Unit = { + def bench(f: Int => Unit): Unit = var i = 0 - while (i < N) { + while i < N do f((i * 4) % M) i += 1 - } - } val r = new Random(0) val rs = new Array[Int](N) (0 until N).map(i => rs(i) = r.nextInt(N)) - def randomBench(f: Int => Unit): Unit = { + def randomBench(f: Int => Unit): Unit = var i = 0 - while (i < N) { + while i < N do f((rs(i) * 4) % M) i += 1 - } - } val rep = 3 info(f"Reading buffers (of size:${M}%,d) ${N}%,d x $rep times") time("sequential getInt", repeat = rep) { block("unsafe array") { var i = 0 - while (i < N) { + while i < N do ub.getInt((i * 4) % M) i += 1 - } } block("unsafe direct") { var i = 0 - while (i < N) { + while i < N do ud.getInt((i * 4) % M) i += 1 - } } block("allocate") { var i = 0 - while (i < N) { + while i < N do hb.getInt((i * 4) % M) i += 1 - } } block("allocateDirect") { var i = 0 - while (i < N) { + while i < N do db.getInt((i * 4) % M) i += 1 - } } } time("random getInt", repeat = rep) { block("unsafe array") { var i = 0 - while (i < N) { + while i < N do ub.getInt((rs(i) * 4) % M) i += 1 - } } block("unsafe direct") { var i = 0 - while (i < N) { + while i < N do ud.getInt((rs(i) * 4) % M) i += 1 - } } block("allocate") { var i = 0 - while (i < N) { + while i < N do hb.getInt((rs(i) * 4) % M) i += 1 - } } block("allocateDirect") { var i = 0 - while (i < N) { + while i < N do db.getInt((rs(i) * 4) % M) i += 1 - } } } } @@ -152,20 +143,21 @@ class MessageBufferTest extends AirSpec with Benchmark { private val builder = Seq.newBuilder[MessageBuffer] builder += MessageBuffer.allocate(10) builder += MessageBuffer.wrap(ByteBuffer.allocate(10)) - if (!universal) builder += MessageBuffer.wrap(ByteBuffer.allocateDirect(10)) + if !universal then + builder += MessageBuffer.wrap(ByteBuffer.allocateDirect(10)) + private val buffers = builder.result() test("convert to ByteBuffer") { - for (t <- buffers) { + for t <- buffers do val bb = t.sliceAsByteBuffer bb.position() shouldBe 0 bb.limit() shouldBe 10 bb.capacity shouldBe 10 - } } test("put ByteBuffer on itself") { - for (t <- buffers) { + for t <- buffers do val b = Array[Byte](0x02, 0x03) val srcArray = ByteBuffer.wrap(b) val srcHeap = ByteBuffer.allocate(b.length) @@ -173,7 +165,7 @@ class MessageBufferTest extends AirSpec with Benchmark { val srcOffHeap = ByteBuffer.allocateDirect(b.length) srcOffHeap.put(b).flip - for (src <- Seq(srcArray, srcHeap, srcOffHeap)) { + for src <- Seq(srcArray, srcHeap, srcOffHeap) do // Write header bytes val header = Array[Byte](0x00, 0x01) t.putBytes(0, header, 0, header.length) @@ -184,12 +176,10 @@ class MessageBufferTest extends AirSpec with Benchmark { t.getByte(1) shouldBe 0x01 t.getByte(2) shouldBe 0x02 t.getByte(3) shouldBe 0x03 - } - } } test("put MessageBuffer on itself") { - for (t <- buffers) { + for t <- buffers do val b = Array[Byte](0x02, 0x03) val srcArray = ByteBuffer.wrap(b) val srcHeap = ByteBuffer.allocate(b.length) @@ -198,9 +188,10 @@ class MessageBufferTest extends AirSpec with Benchmark { srcOffHeap.put(b).flip val builder = Seq.newBuilder[ByteBuffer] builder ++= Seq(srcArray, srcHeap) - if (!universal) builder += srcOffHeap + if !universal then + builder += srcOffHeap - for (src <- builder.result().map(d => MessageBuffer.wrap(d))) { + for src <- builder.result().map(d => MessageBuffer.wrap(d)) do // Write header bytes val header = Array[Byte](0x00, 0x01) t.putBytes(0, header, 0, header.length) @@ -211,23 +202,18 @@ class MessageBufferTest extends AirSpec with Benchmark { t.getByte(1) shouldBe 0x01 t.getByte(2) shouldBe 0x02 t.getByte(3) shouldBe 0x03 - } - } } test("copy sliced buffer") { - def prepareBytes: Array[Byte] = { - Array[Byte](0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07) - } + def prepareBytes: Array[Byte] = Array[Byte](0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07) - def prepareDirectBuffer: ByteBuffer = { + def prepareDirectBuffer: ByteBuffer = val directBuffer = ByteBuffer.allocateDirect(prepareBytes.length) directBuffer.put(prepareBytes) directBuffer.flip directBuffer - } - def checkSliceAndCopyTo(srcBuffer: MessageBuffer, dstBuffer: MessageBuffer) = { + def checkSliceAndCopyTo(srcBuffer: MessageBuffer, dstBuffer: MessageBuffer) = val sliced = srcBuffer.slice(2, 5) sliced.size() shouldBe 5 @@ -247,12 +233,17 @@ class MessageBufferTest extends AirSpec with Benchmark { dstBuffer.getByte(5) shouldBe 0x05 dstBuffer.getByte(6) shouldBe 0x06 dstBuffer.getByte(7) shouldBe 0x07 - } checkSliceAndCopyTo(MessageBuffer.wrap(prepareBytes), MessageBuffer.wrap(prepareBytes)) - checkSliceAndCopyTo(MessageBuffer.wrap(ByteBuffer.wrap(prepareBytes)), MessageBuffer.wrap(ByteBuffer.wrap(prepareBytes))) - if (!universal) { - checkSliceAndCopyTo(MessageBuffer.wrap(prepareDirectBuffer), MessageBuffer.wrap(prepareDirectBuffer)) - } + checkSliceAndCopyTo( + MessageBuffer.wrap(ByteBuffer.wrap(prepareBytes)), + MessageBuffer.wrap(ByteBuffer.wrap(prepareBytes)) + ) + if !universal then + checkSliceAndCopyTo( + MessageBuffer.wrap(prepareDirectBuffer), + MessageBuffer.wrap(prepareDirectBuffer) + ) } -} + +end MessageBufferTest diff --git a/msgpack-core/src/test/scala/org/msgpack/core/example/MessagePackExampleTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/example/MessagePackExampleTest.scala index d0b0e08e..1a1a3a3c 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/example/MessagePackExampleTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/example/MessagePackExampleTest.scala @@ -17,8 +17,9 @@ package org.msgpack.core.example import wvlet.airspec.AirSpec -/** */ -class MessagePackExampleTest extends AirSpec { +/** + */ +class MessagePackExampleTest extends AirSpec: test("example") { @@ -38,4 +39,3 @@ class MessagePackExampleTest extends AirSpec { MessagePackExample.configuration(); } } -} diff --git a/msgpack-core/src/test/scala/org/msgpack/value/RawStringValueImplTest.scala b/msgpack-core/src/test/scala/org/msgpack/value/RawStringValueImplTest.scala index fb340553..73e1edc5 100644 --- a/msgpack-core/src/test/scala/org/msgpack/value/RawStringValueImplTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/value/RawStringValueImplTest.scala @@ -17,7 +17,7 @@ package org.msgpack.value import wvlet.airspec.AirSpec -class RawStringValueImplTest extends AirSpec { +class RawStringValueImplTest extends AirSpec: test("return the same hash code if they are equal") { val str = "a" @@ -29,4 +29,3 @@ class RawStringValueImplTest extends AirSpec { a2 shouldBe a1 a2.hashCode shouldBe a1.hashCode } -} diff --git a/msgpack-core/src/test/scala/org/msgpack/value/ValueFactoryTest.scala b/msgpack-core/src/test/scala/org/msgpack/value/ValueFactoryTest.scala index 3568ba5b..623ca36d 100644 --- a/msgpack-core/src/test/scala/org/msgpack/value/ValueFactoryTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/value/ValueFactoryTest.scala @@ -19,8 +19,9 @@ import org.scalacheck.Gen import wvlet.airspec.AirSpec import wvlet.airspec.spi.PropertyCheck -/** */ -class ValueFactoryTest extends AirSpec with PropertyCheck { +/** + */ +class ValueFactoryTest extends AirSpec with PropertyCheck: private def isValid( v: Value, @@ -37,7 +38,7 @@ class ValueFactoryTest extends AirSpec with PropertyCheck { isRaw: Boolean = false, isNumber: Boolean = false, isTimestamp: Boolean = false - ): Boolean = { + ): Boolean = v.isNilValue shouldBe isNil v.isBooleanValue shouldBe isBoolean v.isIntegerValue shouldBe isInteger @@ -51,7 +52,6 @@ class ValueFactoryTest extends AirSpec with PropertyCheck { v.isNumberValue shouldBe isNumber v.isTimestampValue shouldBe isTimestamp true - } test("ValueFactory") { test("nil") { @@ -66,24 +66,44 @@ class ValueFactoryTest extends AirSpec with PropertyCheck { test("int") { forAll { (v: Int) => - isValid(ValueFactory.newInteger(v), expected = ValueType.INTEGER, isInteger = true, isNumber = true) + isValid( + ValueFactory.newInteger(v), + expected = ValueType.INTEGER, + isInteger = true, + isNumber = true + ) } } test("float") { forAll { (v: Float) => - isValid(ValueFactory.newFloat(v), expected = ValueType.FLOAT, isFloat = true, isNumber = true) + isValid( + ValueFactory.newFloat(v), + expected = ValueType.FLOAT, + isFloat = true, + isNumber = true + ) } } test("string") { forAll { (v: String) => - isValid(ValueFactory.newString(v), expected = ValueType.STRING, isString = true, isRaw = true) + isValid( + ValueFactory.newString(v), + expected = ValueType.STRING, + isString = true, + isRaw = true + ) } } test("array") { forAll { (v: Array[Byte]) => - isValid(ValueFactory.newBinary(v), expected = ValueType.BINARY, isBinary = true, isRaw = true) + isValid( + ValueFactory.newBinary(v), + expected = ValueType.BINARY, + isBinary = true, + isRaw = true + ) } } @@ -97,13 +117,23 @@ class ValueFactoryTest extends AirSpec with PropertyCheck { test("ext") { forAll { (v: Array[Byte]) => - isValid(ValueFactory.newExtension(0, v), expected = ValueType.EXTENSION, isExtension = true, isRaw = false) + isValid( + ValueFactory.newExtension(0, v), + expected = ValueType.EXTENSION, + isExtension = true, + isRaw = false + ) } } test("timestamp") { forAll { (millis: Long) => - isValid(ValueFactory.newTimestamp(millis), expected = ValueType.EXTENSION, isExtension = true, isTimestamp = true) + isValid( + ValueFactory.newTimestamp(millis), + expected = ValueType.EXTENSION, + isExtension = true, + isTimestamp = true + ) } } @@ -111,8 +141,14 @@ class ValueFactoryTest extends AirSpec with PropertyCheck { val posLong = Gen.chooseNum[Long](-31557014167219200L, 31556889864403199L) val posInt = Gen.chooseNum(0, 1000000000 - 1) // NANOS_PER_SECOND forAll(posLong, posInt) { (sec: Long, nano: Int) => - isValid(ValueFactory.newTimestamp(sec, nano), expected = ValueType.EXTENSION, isExtension = true, isTimestamp = true) + isValid( + ValueFactory.newTimestamp(sec, nano), + expected = ValueType.EXTENSION, + isExtension = true, + isTimestamp = true + ) } } } -} + +end ValueFactoryTest diff --git a/msgpack-core/src/test/scala/org/msgpack/value/ValueTest.scala b/msgpack-core/src/test/scala/org/msgpack/value/ValueTest.scala index 83cbde6b..76e2ed27 100644 --- a/msgpack-core/src/test/scala/org/msgpack/value/ValueTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/value/ValueTest.scala @@ -18,14 +18,17 @@ package org.msgpack.value import org.msgpack.core.MessagePackSpec.createMessagePackData import java.math.BigInteger -import org.msgpack.core._ +import org.msgpack.core.* import org.scalacheck.Prop.propBoolean import wvlet.airframe.json.JSON import wvlet.airspec.AirSpec import wvlet.airspec.spi.PropertyCheck -class ValueTest extends AirSpec with PropertyCheck { - private def checkSuccinctType(pack: MessagePacker => Unit, expectedAtMost: MessageFormat): Boolean = { +class ValueTest extends AirSpec with PropertyCheck: + private def checkSuccinctType( + pack: MessagePacker => Unit, + expectedAtMost: MessageFormat + ): Boolean = val b = createMessagePackData(pack) val v1 = MessagePack.newDefaultUnpacker(b).unpackValue() val mf = v1.asIntegerValue().mostSuccinctMessageFormat() @@ -39,7 +42,6 @@ class ValueTest extends AirSpec with PropertyCheck { mf2.ordinal() <= expectedAtMost.ordinal() shouldBe true true - } test("Value") { test("tell most succinct integer type") { @@ -61,14 +63,17 @@ class ValueTest extends AirSpec with PropertyCheck { forAll { (v: Long) => v > 0 ==> { // Create value between 2^63-1 < v <= 2^64-1 - checkSuccinctType(_.packBigInteger(BigInteger.valueOf(Long.MaxValue).add(BigInteger.valueOf(v))), MessageFormat.UINT64) + checkSuccinctType( + _.packBigInteger(BigInteger.valueOf(Long.MaxValue).add(BigInteger.valueOf(v))), + MessageFormat.UINT64 + ) } } } test("produce json strings") { - import ValueFactory._ + import ValueFactory.* newNil().toJson shouldBe "null" newNil().toString shouldBe "null" @@ -88,7 +93,8 @@ class ValueTest extends AirSpec with PropertyCheck { newArray(newInteger(0), newString("hello")).toJson shouldBe "[0,\"hello\"]" newArray(newInteger(0), newString("hello")).toString shouldBe "[0,\"hello\"]" - newArray(newArray(newString("Apple"), newFloat(0.2)), newNil()).toJson shouldBe """[["Apple",0.2],null]""" + newArray(newArray(newString("Apple"), newFloat(0.2)), newNil()).toJson shouldBe + """[["Apple",0.2],null]""" // Map value val m = newMapBuilder() @@ -112,7 +118,7 @@ class ValueTest extends AirSpec with PropertyCheck { } test("check appropriate range for integers") { - import ValueFactory._ + import ValueFactory.* import java.lang.Byte import java.lang.Short @@ -142,4 +148,5 @@ class ValueTest extends AirSpec with PropertyCheck { } } } -} + +end ValueTest diff --git a/msgpack-core/src/test/scala/org/msgpack/value/ValueTypeTest.scala b/msgpack-core/src/test/scala/org/msgpack/value/ValueTypeTest.scala index fc81bdeb..7b992f28 100644 --- a/msgpack-core/src/test/scala/org/msgpack/value/ValueTypeTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/value/ValueTypeTest.scala @@ -15,70 +15,59 @@ // package org.msgpack.value -import org.msgpack.core.MessagePack.Code._ +import org.msgpack.core.MessagePack.Code.* import org.msgpack.core.{MessageFormat, MessageFormatException} import wvlet.airspec.AirSpec -/** Created on 2014/05/06. +/** + * Created on 2014/05/06. */ -class ValueTypeTest extends AirSpec { +class ValueTypeTest extends AirSpec: test("lookup ValueType from a byte value") { - def check(b: Byte, tpe: ValueType): Unit = { - MessageFormat.valueOf(b).getValueType shouldBe tpe - } + def check(b: Byte, tpe: ValueType): Unit = MessageFormat.valueOf(b).getValueType shouldBe tpe - for (i <- 0 until 0x7f) { + for i <- 0 until 0x7f do check(i.toByte, ValueType.INTEGER) - } - for (i <- 0x80 until 0x8f) { + for i <- 0x80 until 0x8f do check(i.toByte, ValueType.MAP) - } - for (i <- 0x90 until 0x9f) { + for i <- 0x90 until 0x9f do check(i.toByte, ValueType.ARRAY) - } check(NIL, ValueType.NIL) - try { + try MessageFormat.valueOf(NEVER_USED).getValueType fail("NEVER_USED type should not have ValueType") - } catch { + catch case e: MessageFormatException => // OK - } check(TRUE, ValueType.BOOLEAN) check(FALSE, ValueType.BOOLEAN) - for (t <- Seq(BIN8, BIN16, BIN32)) { + for t <- Seq(BIN8, BIN16, BIN32) do check(t, ValueType.BINARY) - } - for (t <- Seq(FIXEXT1, FIXEXT2, FIXEXT4, FIXEXT8, FIXEXT16, EXT8, EXT16, EXT32)) { + for t <- Seq(FIXEXT1, FIXEXT2, FIXEXT4, FIXEXT8, FIXEXT16, EXT8, EXT16, EXT32) do check(t, ValueType.EXTENSION) - } - for (t <- Seq(INT8, INT16, INT32, INT64, UINT8, UINT16, UINT32, UINT64)) { + for t <- Seq(INT8, INT16, INT32, INT64, UINT8, UINT16, UINT32, UINT64) do check(t, ValueType.INTEGER) - } - for (t <- Seq(STR8, STR16, STR32)) { + for t <- Seq(STR8, STR16, STR32) do check(t, ValueType.STRING) - } - for (t <- Seq(FLOAT32, FLOAT64)) { + for t <- Seq(FLOAT32, FLOAT64) do check(t, ValueType.FLOAT) - } - for (t <- Seq(ARRAY16, ARRAY32)) { + for t <- Seq(ARRAY16, ARRAY32) do check(t, ValueType.ARRAY) - } - for (i <- 0xe0 until 0xff) { + for i <- 0xe0 until 0xff do check(i.toByte, ValueType.INTEGER) - } } -} + +end ValueTypeTest diff --git a/msgpack-core/src/test/scala/org/msgpack/value/VariableTest.scala b/msgpack-core/src/test/scala/org/msgpack/value/VariableTest.scala index f9a1c2a0..4eabdbd7 100644 --- a/msgpack-core/src/test/scala/org/msgpack/value/VariableTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/value/VariableTest.scala @@ -21,11 +21,12 @@ import wvlet.airspec.spi.PropertyCheck import java.time.Instant import java.util -import scala.jdk.CollectionConverters._ +import scala.jdk.CollectionConverters.* -/** */ -class VariableTest extends AirSpec with PropertyCheck { - private def check(pack: MessagePacker => Unit, checker: Variable => Unit): Unit = { +/** + */ +class VariableTest extends AirSpec with PropertyCheck: + private def check(pack: MessagePacker => Unit, checker: Variable => Unit): Unit = val packer = MessagePack.newDefaultBufferPacker() pack(packer) val msgpack = packer.toByteArray @@ -35,11 +36,11 @@ class VariableTest extends AirSpec with PropertyCheck { unpacker.unpackValue(v) checker(v) unpacker.close() - } - /** Test Value -> MsgPack -> Value + /** + * Test Value -> MsgPack -> Value */ - private def roundTrip(v: Value): Unit = { + private def roundTrip(v: Value): Unit = val packer = MessagePack.newDefaultBufferPacker() v.writeTo(packer) val msgpack = packer.toByteArray @@ -48,7 +49,6 @@ class VariableTest extends AirSpec with PropertyCheck { unpacker.close() v shouldBe v1 v.immutableValue() shouldBe v1 - } private def validateValue[V <: Value]( v: V, @@ -62,7 +62,7 @@ class VariableTest extends AirSpec with PropertyCheck { asMap: Boolean = false, asExtension: Boolean = false, asTimestamp: Boolean = false - ): V = { + ): V = v.isNilValue shouldBe asNil v.isBooleanValue shouldBe asBoolean v.isIntegerValue shouldBe asInteger @@ -76,203 +76,200 @@ class VariableTest extends AirSpec with PropertyCheck { v.isExtensionValue shouldBe asExtension | asTimestamp v.isTimestampValue shouldBe asTimestamp - if (asNil) { + if asNil then v.getValueType shouldBe ValueType.NIL roundTrip(v) - } else { + else intercept[MessageTypeCastException] { v.asNilValue() } - } - if (asBoolean) { + if asBoolean then v.getValueType shouldBe ValueType.BOOLEAN roundTrip(v) - } else { + else intercept[MessageTypeCastException] { v.asBooleanValue() } - } - if (asInteger) { + if asInteger then v.getValueType shouldBe ValueType.INTEGER roundTrip(v) - } else { + else intercept[MessageTypeCastException] { v.asIntegerValue() } - } - if (asFloat) { + if asFloat then v.getValueType shouldBe ValueType.FLOAT roundTrip(v) - } else { + else intercept[MessageTypeCastException] { v.asFloatValue() } - } - if (asBinary | asString) { + if asBinary | asString then v.asRawValue() roundTrip(v) - } else { + else intercept[MessageTypeCastException] { v.asRawValue() } - } - if (asBinary) { + if asBinary then v.getValueType shouldBe ValueType.BINARY roundTrip(v) - } else { + else intercept[MessageTypeCastException] { v.asBinaryValue() } - } - if (asString) { + if asString then v.getValueType shouldBe ValueType.STRING roundTrip(v) - } else { + else intercept[MessageTypeCastException] { v.asStringValue() } - } - if (asArray) { + if asArray then v.getValueType shouldBe ValueType.ARRAY roundTrip(v) - } else { + else intercept[MessageTypeCastException] { v.asArrayValue() } - } - if (asMap) { + if asMap then v.getValueType shouldBe ValueType.MAP roundTrip(v) - } else { + else intercept[MessageTypeCastException] { v.asMapValue() } - } - if (asExtension) { + if asExtension then v.getValueType shouldBe ValueType.EXTENSION roundTrip(v) - } else { + else intercept[MessageTypeCastException] { v.asExtensionValue() } - } - if (asTimestamp) { + if asTimestamp then v.getValueType shouldBe ValueType.EXTENSION roundTrip(v) - } else { + else intercept[MessageTypeCastException] { v.asTimestampValue() } - } v - } + + end validateValue test("Variable") { test("read nil") { check( _.packNil, - checker = { v => - val iv = validateValue(v.asNilValue(), asNil = true) - iv.toJson shouldBe "null" - } + checker = + v => + val iv = validateValue(v.asNilValue(), asNil = true) + iv.toJson shouldBe "null" ) } test("read integers") { - forAll { i: Int => - check( - _.packInt(i), - checker = { v => - val iv = validateValue(v.asIntegerValue(), asInteger = true) - iv.asInt() shouldBe i - iv.asLong() shouldBe i.toLong - } - ) + forAll { (i: Int) => + check( + _.packInt(i), + checker = + v => + val iv = validateValue(v.asIntegerValue(), asInteger = true) + iv.asInt() shouldBe i + iv.asLong() shouldBe i.toLong + ) } } test("read double") { - forAll { x: Double => - check( - _.packDouble(x), - checker = { v => - val iv = validateValue(v.asFloatValue(), asFloat = true) - // iv.toDouble shouldBe v - // iv.toFloat shouldBe x.toFloat - } - ) + forAll { (x: Double) => + check( + _.packDouble(x), + checker = + v => + val iv = validateValue(v.asFloatValue(), asFloat = true) + // iv.toDouble shouldBe v + // iv.toFloat shouldBe x.toFloat + ) } } test("read boolean") { - forAll { x: Boolean => - check( - _.packBoolean(x), - checker = { v => - val iv = validateValue(v.asBooleanValue(), asBoolean = true) - iv.getBoolean shouldBe x - } - ) + forAll { (x: Boolean) => + check( + _.packBoolean(x), + checker = + v => + val iv = validateValue(v.asBooleanValue(), asBoolean = true) + iv.getBoolean shouldBe x + ) } } test("read binary") { - forAll { x: Array[Byte] => + forAll { (x: Array[Byte]) => check( { packer => - packer.packBinaryHeader(x.length); packer.addPayload(x) + packer.packBinaryHeader(x.length); + packer.addPayload(x) }, - checker = { v => - val iv = validateValue(v.asBinaryValue(), asBinary = true) - util.Arrays.equals(iv.asByteArray(), x) - } + checker = + v => + val iv = validateValue(v.asBinaryValue(), asBinary = true) + util.Arrays.equals(iv.asByteArray(), x) ) } } test("read string") { - forAll { x: String => - check( - _.packString(x), - checker = { v => - val iv = validateValue(v.asStringValue(), asString = true) - iv.asString() shouldBe x - } - ) + forAll { (x: String) => + check( + _.packString(x), + checker = + v => + val iv = validateValue(v.asStringValue(), asString = true) + iv.asString() shouldBe x + ) } } test("read array") { - forAll { x: Seq[Int] => + forAll { (x: Seq[Int]) => check( { packer => packer.packArrayHeader(x.size) - x.foreach { packer.packInt(_) } + x.foreach { + packer.packInt(_) + } }, - checker = { v => - val iv = validateValue(v.asArrayValue(), asArray = true) - val lst = iv.list().asScala.map(_.asIntegerValue().toInt) - lst shouldBe x - } + checker = + v => + val iv = validateValue(v.asArrayValue(), asArray = true) + val lst = iv.list().asScala.map(_.asIntegerValue().toInt) + lst shouldBe x ) } } test("read map") { - forAll { x: Seq[Int] => + forAll { (x: Seq[Int]) => // Generate map with unique keys - val map = x.zipWithIndex.map { case (x, i) => (s"key-${i}", x) } + val map = x + .zipWithIndex + .map { case (x, i) => + (s"key-${i}", x) + } check( { packer => packer.packMapHeader(map.size) @@ -281,27 +278,32 @@ class VariableTest extends AirSpec with PropertyCheck { packer.packInt(x._2) } }, - checker = { v => - val iv = validateValue(v.asMapValue(), asMap = true) - val lst = iv.map().asScala.map(p => (p._1.asStringValue().asString(), p._2.asIntegerValue().asInt())).toSeq - lst.sortBy(_._1) shouldBe map.sortBy(_._1) - } + checker = + v => + val iv = validateValue(v.asMapValue(), asMap = true) + val lst = + iv.map() + .asScala + .map(p => (p._1.asStringValue().asString(), p._2.asIntegerValue().asInt())) + .toSeq + lst.sortBy(_._1) shouldBe map.sortBy(_._1) ) } } test("read timestamps") { - forAll { millis: Long => - val i = Instant.ofEpochMilli(millis) - check( - _.packTimestamp(i), - checker = { v => - val ts = validateValue(v.asTimestampValue(), asTimestamp = true) - ts.isTimestampValue shouldBe true - ts.toInstant shouldBe i - } - ) + forAll { (millis: Long) => + val i = Instant.ofEpochMilli(millis) + check( + _.packTimestamp(i), + checker = + v => + val ts = validateValue(v.asTimestampValue(), asTimestamp = true) + ts.isTimestampValue shouldBe true + ts.toInstant shouldBe i + ) } } } -} + +end VariableTest From 2bb48340b5159b96d14b8bb73fd293ce08ff89db Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 19 Jul 2025 10:35:17 -0700 Subject: [PATCH 15/43] Upgrade Scala to 3.7.1 and use Scala 3 code format style (#899) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Upgrade Scala to 3.7.1 and update code format style - Upgrade Scala version from 2.13.12 to 3.7.1 in build.sbt - Update scalafmt.conf to use Scala 3 dialect and modern formatting rules - Fix Scala 3 compatibility issues in test files: - Update lambda syntax to use parentheses around parameters - Remove deprecated underscore suffix from function references - Apply Scala 3 formatting with scalafmt 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Update CLAUDE.md for Scala 3.7.1 and modern sbt syntax - Fix build command to use modern sbt syntax: Test / compile instead of test:compile - Update Scala version reference to 3.7.1 in testing structure - Update scalafmt configuration notes to reflect Scala 3 dialect and 100 char limit * Update CLAUDE.md to recommend latest Scala 3 version - Change specific version reference to 'always use the latest Scala 3 version' - This ensures the documentation remains current as new Scala 3 versions are released * Update README.md for modern sbt syntax and Scala 3 - Fix sbt command syntax: change test:compile to 'Test / compile' - Add note about Scala 3 dialect and latest version recommendation - Ensure developer documentation matches current project configuration * Update scalafmtAll command description - Change comment from 'Format Scala test code' to 'Format all Scala and sbt code' - More accurately reflects what scalafmtAll does (formats all Scala files, not just tests) - Apply change to both README.md and CLAUDE.md for consistency --------- Co-authored-by: Claude --- .scalafmt.conf | 2 +- CLAUDE.md | 8 +- README.md | 5 +- .../org/msgpack/core/MessagePackTest.scala | 6 +- .../org/msgpack/core/MessagePackerTest.scala | 2 +- .../msgpack/core/MessageUnpackerTest.scala | 10 +-- .../org/msgpack/value/VariableTest.scala | 80 +++++++++---------- 7 files changed, 57 insertions(+), 56 deletions(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index fcadd98d..e8563baf 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = 3.9.4 +version = 3.9.8 project.layout = StandardConvention runner.dialect = scala3 maxColumn = 100 diff --git a/CLAUDE.md b/CLAUDE.md index e01643b5..2e72e982 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,7 +13,7 @@ MessagePack-Java is a binary serialization library that provides a fast and comp ### Build and Compile ```bash ./sbt compile # Compile source code -./sbt test:compile # Compile source and test code +./sbt "Test / compile" # Compile source and test code ./sbt package # Create JAR files ``` @@ -31,7 +31,7 @@ MessagePack-Java is a binary serialization library that provides a fast and comp ### Code Quality ```bash ./sbt jcheckStyle # Run checkstyle (Facebook Presto style) -./sbt scalafmtAll # Format Scala test code +./sbt scalafmtAll # Format all Scala and sbt code ``` ### Publishing @@ -66,7 +66,7 @@ The msgpack-jackson module provides: - Extension type support including timestamps ### Testing Structure -- **msgpack-core tests**: Written in Scala using AirSpec framework +- **msgpack-core tests**: Written in Scala (always use the latest Scala 3 version) using AirSpec framework - Location: `msgpack-core/src/test/scala/` - **msgpack-jackson tests**: Written in Java using JUnit - Location: `msgpack-jackson/src/test/java/` @@ -81,7 +81,7 @@ For JDK 17+ compatibility, these options are automatically added: ## Code Style Requirements - Java code follows Facebook Presto style (enforced by checkstyle) -- Scala test code uses Scalafmt with 180 character line limit +- Scala test code uses Scalafmt with Scala 3 dialect and 100 character line limit - Checkstyle runs automatically during compilation - No external dependencies allowed in msgpack-core diff --git a/README.md b/README.md index 34a3f277..54d1877a 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ msgpack-java uses [sbt](http://www.scala-sbt.org/) for building the projects. Fo Coding style * msgpack-java uses [the same coding style](https://github.com/airlift/codestyle) with Facebook Presto * [IntelliJ setting file](https://raw.githubusercontent.com/airlift/codestyle/master/IntelliJIdea14/Airlift.xml) + * Scala test code uses Scalafmt with Scala 3 dialect (always use the latest Scala 3 version) ### Basic sbt commands Enter the sbt console: @@ -76,14 +77,14 @@ $ ./sbt Here is a list of sbt commands for daily development: ``` > ~compile # Compile source codes -> ~test:compile # Compile both source and test codes +> ~"Test / compile" # Compile both source and test codes > ~test # Run tests upon source code change > ~testOnly *MessagePackTest # Run tests in the specified class > ~testOnly *MessagePackTest -- (pattern) # Run tests matching the pattern > project msgpack-core # Focus on a specific project > package # Create a jar file in the target folder of each project > jcheckStyle # Run check style -> scalafmtAll # Reformat code +> scalafmtAll # Format all Scala and sbt code ``` ### Publishing diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala index 0a4328d8..b5541393 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala @@ -376,7 +376,7 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark: test("report errors when packing/unpacking malformed strings") { pending("We need to produce malformed utf-8 strings in Java 8") // Create 100 malformed UTF8 Strings - val r = new Random(0) + val r = new Random(0) val malformedStrings = Iterator .continually { val b = new Array[Byte](10) @@ -580,12 +580,12 @@ class MessagePackTest extends AirSpec with PropertyCheck with Benchmark: kvs .grouped(2) - .map((kvp: Array[Value]) => + .map { (kvp: Array[Value]) => val k = kvp(0) val v = kvp(1) (k.asStringValue().asString, v.asStringValue().asString) - ) + } .toMap } .toList diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala index c1b4b0a4..7ff5d82e 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala @@ -211,7 +211,7 @@ class MessagePackerTest extends AirSpec with Benchmark: } test("compute totalWrittenBytes") { - val out = new ByteArrayOutputStream + val out = new ByteArrayOutputStream val packerTotalWrittenBytes = withResource(MessagePack.newDefaultPacker(out)) { packer => packer diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala index ae25d284..adab4708 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala @@ -30,7 +30,7 @@ import scala.util.Random object MessageUnpackerTest: class SplitMessageBufferInput(array: Array[Array[Byte]]) extends MessageBufferInput: - var cursor = 0 + var cursor = 0 override def next(): MessageBuffer = if cursor < array.length then val a = array(cursor) @@ -45,7 +45,7 @@ import org.msgpack.core.MessageUnpackerTest.* class MessageUnpackerTest extends AirSpec with Benchmark: - private val universal = MessageBuffer.allocate(0).isInstanceOf[MessageBufferU] + private val universal = MessageBuffer.allocate(0).isInstanceOf[MessageBufferU] private def testData: Array[Byte] = val out = new ByteArrayOutputStream() val packer = MessagePack.newDefaultPacker(out) @@ -435,7 +435,7 @@ class MessageUnpackerTest extends AirSpec with Benchmark: val t = time("skip performance", repeat = N) { block("v6") { - val v6 = new org.msgpack.MessagePack() + val v6 = new org.msgpack.MessagePack() val unpacker = new org.msgpack.unpacker.MessagePackUnpacker(v6, new ByteArrayInputStream(data)) var count = 0 @@ -567,7 +567,7 @@ class MessageUnpackerTest extends AirSpec with Benchmark: val t = time("unpack performance", repeat = N) { block("v6") { - val v6 = new org.msgpack.MessagePack() + val v6 = new org.msgpack.MessagePack() val unpacker = new org.msgpack.unpacker.MessagePackUnpacker(v6, new ByteArrayInputStream(data)) var count = 0 @@ -655,7 +655,7 @@ class MessageUnpackerTest extends AirSpec with Benchmark: time("unpackBinary", repeat = 100) { block("v6") { - val v6 = new org.msgpack.MessagePack() + val v6 = new org.msgpack.MessagePack() val unpacker = new org.msgpack.unpacker.MessagePackUnpacker(v6, new ByteArrayInputStream(b)) var i = 0 diff --git a/msgpack-core/src/test/scala/org/msgpack/value/VariableTest.scala b/msgpack-core/src/test/scala/org/msgpack/value/VariableTest.scala index 4eabdbd7..2f3cbf9c 100644 --- a/msgpack-core/src/test/scala/org/msgpack/value/VariableTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/value/VariableTest.scala @@ -181,39 +181,39 @@ class VariableTest extends AirSpec with PropertyCheck: test("read integers") { forAll { (i: Int) => - check( - _.packInt(i), - checker = - v => - val iv = validateValue(v.asIntegerValue(), asInteger = true) - iv.asInt() shouldBe i - iv.asLong() shouldBe i.toLong - ) + check( + _.packInt(i), + checker = + v => + val iv = validateValue(v.asIntegerValue(), asInteger = true) + iv.asInt() shouldBe i + iv.asLong() shouldBe i.toLong + ) } } test("read double") { forAll { (x: Double) => - check( - _.packDouble(x), - checker = - v => - val iv = validateValue(v.asFloatValue(), asFloat = true) - // iv.toDouble shouldBe v - // iv.toFloat shouldBe x.toFloat - ) + check( + _.packDouble(x), + checker = + v => + val iv = validateValue(v.asFloatValue(), asFloat = true) + // iv.toDouble shouldBe v + // iv.toFloat shouldBe x.toFloat + ) } } test("read boolean") { forAll { (x: Boolean) => - check( - _.packBoolean(x), - checker = - v => - val iv = validateValue(v.asBooleanValue(), asBoolean = true) - iv.getBoolean shouldBe x - ) + check( + _.packBoolean(x), + checker = + v => + val iv = validateValue(v.asBooleanValue(), asBoolean = true) + iv.getBoolean shouldBe x + ) } } @@ -234,13 +234,13 @@ class VariableTest extends AirSpec with PropertyCheck: test("read string") { forAll { (x: String) => - check( - _.packString(x), - checker = - v => - val iv = validateValue(v.asStringValue(), asString = true) - iv.asString() shouldBe x - ) + check( + _.packString(x), + checker = + v => + val iv = validateValue(v.asStringValue(), asString = true) + iv.asString() shouldBe x + ) } } @@ -280,7 +280,7 @@ class VariableTest extends AirSpec with PropertyCheck: }, checker = v => - val iv = validateValue(v.asMapValue(), asMap = true) + val iv = validateValue(v.asMapValue(), asMap = true) val lst = iv.map() .asScala @@ -293,15 +293,15 @@ class VariableTest extends AirSpec with PropertyCheck: test("read timestamps") { forAll { (millis: Long) => - val i = Instant.ofEpochMilli(millis) - check( - _.packTimestamp(i), - checker = - v => - val ts = validateValue(v.asTimestampValue(), asTimestamp = true) - ts.isTimestampValue shouldBe true - ts.toInstant shouldBe i - ) + val i = Instant.ofEpochMilli(millis) + check( + _.packTimestamp(i), + checker = + v => + val ts = validateValue(v.asTimestampValue(), asTimestamp = true) + ts.isTimestampValue shouldBe true + ts.toInstant shouldBe i + ) } } } From fe697bc1b401d0ed2e5da77f6164f1c138647351 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 19 Jul 2025 10:40:59 -0700 Subject: [PATCH 16/43] Update README.md publishing instructions for Sonatype Central (#900) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove references to deprecated sbt-sonatype plugin - Update credentials setup to use new Sonatype Central format - Replace sonatypeBundleRelease with sonaRelease command - Add environment variable alternative for credentials - Update host from oss.sonatype.org to central.sonatype.com 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude --- README.md | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 54d1877a..f23af0b7 100644 --- a/README.md +++ b/README.md @@ -108,27 +108,38 @@ A new release note will be generated automatically at the [GitHub Releases](http #### Publishing to Sonatype from Local Machine -If you need to publish to Maven central using a local machine, you need to configure [sbt-sonatype](https://github.com/xerial/sbt-sonatype) plugin. First set Sonatype account information (user name and password) in the global sbt settings. To protect your password, never include this file in your project. +If you need to publish to Maven central using a local machine, you need to configure credentials for Sonatype Central. First set Sonatype account information (user name and password) in the global sbt settings. To protect your password, never include this file in your project. -___$HOME/.sbt/(sbt-version)/sonatype.sbt___ +___$HOME/.sbt/1.0/credentials.sbt___ ``` -credentials += Credentials("Sonatype Nexus Repository Manager", - "oss.sonatype.org", - "(Sonatype user name)", - "(Sonatype password)") +credentials += Credentials(Path.userHome / ".sbt" / "sonatype_central_credentials") +``` + +Then create a credentials file at `~/.sbt/sonatype_central_credentials`: + +``` +host=central.sonatype.com +user= +password= +``` + +Alternatively, you can use environment variables: +```bash +export SONATYPE_USERNAME= +export SONATYPE_PASSWORD= ``` You may also need to configure GPG. See the instruction in [sbt-pgp](https://github.com/sbt/sbt-pgp). -Then, run `publishedSigned` followed by `sonatypeBundleRelease`: +Then, run `publishSigned` followed by `sonaRelease`: ``` # [optional] When you need to perform the individual release steps manually, use the following commands: > publishSigned # Publish GPG signed artifacts to the Sonatype repository -> sonatypeBundleRelease # Publish to the Maven Central (It will be synched within less than 4 hours) +> sonaRelease # Publish to the Maven Central (It will be synched within less than 4 hours) ``` -If some sporadic error happens (e.g., Sonatype timeout), rerun `sonatypeBundleRelease` again. +If some sporadic error happens (e.g., Sonatype timeout), rerun `sonaRelease` again. ### Project Structure From 4e6458a23978c91c74ffa843e7692b5e75b40b3a Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 19 Jul 2025 10:45:17 -0700 Subject: [PATCH 17/43] Skip CI tests for non-code changes using dorny/paths-filter (#901) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add dorny/paths-filter action to detect file changes - Skip code format and test jobs when only docs are changed - Improve CI efficiency by running tests only when needed 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude --- .github/workflows/CI.yml | 43 ++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 31f824e4..11c3501b 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -2,27 +2,42 @@ name: CI on: pull_request: - paths: - - '**.scala' - - '**.java' - - '**.sbt' - - '.github/workflows/**.yml' - - 'project/build.properties' push: branches: - main - paths: - - '**.scala' - - '**.java' - - '**.sbt' - - '.github/workflows/**.yml' - - 'project/build.properties' - workflow_dispatch: + workflow_dispatch: jobs: + changes: + runs-on: ubuntu-latest + outputs: + code: ${{ steps.changes.outputs.code }} + docs: ${{ steps.changes.outputs.docs }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: dorny/paths-filter@v3 + id: changes + with: + filters: | + code: + - '**.scala' + - '**.java' + - '**.sbt' + - '.github/workflows/**.yml' + - 'project/build.properties' + - 'msgpack-core/**' + - 'msgpack-jackson/**' + docs: + - '**.md' + - '**.txt' + - 'LICENSE' + code_format: name: Code Format runs-on: ubuntu-latest + needs: changes + if: ${{ needs.changes.outputs.code == 'true' }} steps: - uses: actions/checkout@v4 - name: jcheckstyle @@ -31,6 +46,8 @@ jobs: test: name: Test JDK${{ matrix.java }} runs-on: ubuntu-latest + needs: changes + if: ${{ needs.changes.outputs.code == 'true' }} strategy: matrix: java: ['8', '11', '17', '21', '24'] From a08b9eb295c6fdfd203bb8346a3f4b955df3dfd1 Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Sat, 19 Jul 2025 19:58:41 +0200 Subject: [PATCH 18/43] Update jackson-databind to 2.18.4 (#886) * Update jackson-databind to 2.18.4 * Update build.sbt --------- Co-authored-by: Taro L. Saito --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 3d6ba320..135145fd 100644 --- a/build.sbt +++ b/build.sbt @@ -133,7 +133,7 @@ lazy val msgpackJackson = "org.msgpack.jackson.dataformat" ), libraryDependencies ++= Seq( - "com.fasterxml.jackson.core" % "jackson-databind" % "2.18.2", + "com.fasterxml.jackson.core" % "jackson-databind" % "2.18.4", junitJupiter, junitVintage, "org.apache.commons" % "commons-math3" % "3.6.1" % "test" From 3021550c18f65985db7ea2e0fd12339d0c75fd1e Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 19 Jul 2025 11:02:02 -0700 Subject: [PATCH 19/43] Add scalafmtCheckAll to code format CI (#902) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This ensures Scala code formatting is validated in CI alongside Java checkstyle. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude --- .github/workflows/CI.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 11c3501b..4c49c411 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -42,6 +42,8 @@ jobs: - uses: actions/checkout@v4 - name: jcheckstyle run: ./sbt jcheckStyle + - name: scalafmtCheckAll + run: ./sbt scalafmtCheckAll test: name: Test JDK${{ matrix.java }} From 799e2d188b13b07704d1708d4e10283fe6dfdc8f Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 19 Jul 2025 12:40:06 -0700 Subject: [PATCH 20/43] Fix Jackson deprecation warnings in MessagePackFactory (#903) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix Jackson deprecation warnings in MessagePackFactory Replace deprecated _createContext(Object, boolean) calls with _createContext(ContentReference, boolean) to eliminate warnings when running tests with Jackson 2.18.4. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Fix Jackson deprecation warnings in MessagePackParserTest Replace deprecated JsonParser methods with their current equivalents: - getCurrentName() → currentName() - getTokenLocation() → currentTokenLocation() - getCurrentLocation() → currentLocation() 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Fix all remaining Jackson deprecation warnings - Replace deprecated ParserMinimalBase constructor with StreamReadConstraints - Add non-deprecated location methods (currentTokenLocation, currentLocation) - Update GeneratorBase constructor to use 4-parameter form with IOContext and JsonWriteContext - Add new createKeySerializer method signature for Jackson 2.18 - Keep deprecated methods for backward compatibility All tests pass and Jackson deprecation warnings are eliminated. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --------- Co-authored-by: Claude --- .../dataformat/MessagePackFactory.java | 5 ++- .../dataformat/MessagePackGenerator.java | 10 ++++- .../jackson/dataformat/MessagePackParser.java | 21 ++++++++-- .../MessagePackSerializerFactory.java | 9 +++++ .../dataformat/MessagePackParserTest.java | 38 +++++++++---------- 5 files changed, 57 insertions(+), 26 deletions(-) diff --git a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackFactory.java b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackFactory.java index dbd2a465..865c0cf4 100644 --- a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackFactory.java +++ b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackFactory.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.io.ContentReference; import com.fasterxml.jackson.core.io.IOContext; import org.msgpack.core.MessagePack; import org.msgpack.core.annotations.VisibleForTesting; @@ -111,7 +112,7 @@ public JsonGenerator createGenerator(Writer w) public JsonParser createParser(byte[] data) throws IOException { - IOContext ioContext = _createContext(data, false); + IOContext ioContext = _createContext(ContentReference.rawReference(data), false); return _createParser(data, 0, data.length, ioContext); } @@ -119,7 +120,7 @@ public JsonParser createParser(byte[] data) public JsonParser createParser(InputStream in) throws IOException { - IOContext ioContext = _createContext(in, false); + IOContext ioContext = _createContext(ContentReference.rawReference(in), false); return _createParser(in, ioContext); } diff --git a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackGenerator.java b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackGenerator.java index abb5089e..3dde5604 100644 --- a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackGenerator.java +++ b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackGenerator.java @@ -19,7 +19,11 @@ import com.fasterxml.jackson.core.ObjectCodec; import com.fasterxml.jackson.core.SerializableString; import com.fasterxml.jackson.core.base.GeneratorBase; +import com.fasterxml.jackson.core.io.ContentReference; +import com.fasterxml.jackson.core.io.IOContext; import com.fasterxml.jackson.core.io.SerializedString; +import com.fasterxml.jackson.core.json.JsonWriteContext; +import com.fasterxml.jackson.core.util.BufferRecycler; import org.msgpack.core.MessagePack; import org.msgpack.core.MessagePacker; import org.msgpack.core.annotations.Nullable; @@ -185,6 +189,7 @@ else if (value instanceof NodeArray) { } // This is an internal constructor for nested serialization. + @SuppressWarnings("deprecation") private MessagePackGenerator( int features, ObjectCodec codec, @@ -192,7 +197,7 @@ private MessagePackGenerator( MessagePack.PackerConfig packerConfig, boolean supportIntegerKeys) { - super(features, codec); + super(features, codec, new IOContext(new BufferRecycler(), ContentReference.rawReference(out), false), JsonWriteContext.createRootContext(null)); this.output = out; this.messagePacker = packerConfig.newPacker(out); this.packerConfig = packerConfig; @@ -200,6 +205,7 @@ private MessagePackGenerator( this.supportIntegerKeys = supportIntegerKeys; } + @SuppressWarnings("deprecation") public MessagePackGenerator( int features, ObjectCodec codec, @@ -209,7 +215,7 @@ public MessagePackGenerator( boolean supportIntegerKeys) throws IOException { - super(features, codec); + super(features, codec, new IOContext(new BufferRecycler(), ContentReference.rawReference(out), false), JsonWriteContext.createRootContext(null)); this.output = out; this.messagePacker = packerConfig.newPacker(getMessageBufferOutputForOutputStream(out, reuseResourceInGenerator)); this.packerConfig = packerConfig; diff --git a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackParser.java b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackParser.java index e59b7f57..72aeed20 100644 --- a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackParser.java +++ b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackParser.java @@ -106,7 +106,7 @@ private MessagePackParser(IOContext ctxt, boolean reuseResourceInParser) throws IOException { - super(features); + super(features, ctxt.streamReadConstraints()); this.codec = objectCodec; ioContext = ctxt; @@ -583,15 +583,29 @@ public JsonStreamContext getParsingContext() } @Override + public JsonLocation currentTokenLocation() + { + return new JsonLocation(ioContext.contentReference(), tokenPosition, -1, -1); + } + + @Override + public JsonLocation currentLocation() + { + return new JsonLocation(ioContext.contentReference(), currentPosition, -1, -1); + } + + @Override + @Deprecated public JsonLocation getTokenLocation() { - return new JsonLocation(ioContext.getSourceReference(), tokenPosition, -1, -1, (int) tokenPosition); + return currentTokenLocation(); } @Override + @Deprecated public JsonLocation getCurrentLocation() { - return new JsonLocation(ioContext.getSourceReference(), currentPosition, -1, -1, (int) currentPosition); + return currentLocation(); } @Override @@ -627,6 +641,7 @@ public boolean isCurrentFieldId() } @Override + @Deprecated public String getCurrentName() throws IOException { diff --git a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackSerializerFactory.java b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackSerializerFactory.java index fa2148dc..4100ef4c 100644 --- a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackSerializerFactory.java +++ b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackSerializerFactory.java @@ -16,8 +16,10 @@ package org.msgpack.jackson.dataformat; import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializationConfig; +import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.cfg.SerializerFactoryConfig; import com.fasterxml.jackson.databind.ser.BeanSerializerFactory; @@ -43,6 +45,13 @@ public MessagePackSerializerFactory(SerializerFactoryConfig config) } @Override + public JsonSerializer createKeySerializer(SerializerProvider prov, JavaType keyType, JsonSerializer defaultImpl) throws JsonMappingException + { + return new MessagePackKeySerializer(); + } + + @Override + @Deprecated public JsonSerializer createKeySerializer(SerializationConfig config, JavaType keyType, JsonSerializer defaultImpl) { return new MessagePackKeySerializer(); diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackParserTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackParserTest.java index c0bab053..256c4332 100644 --- a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackParserTest.java +++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackParserTest.java @@ -317,43 +317,43 @@ public void testMessagePackParserDirectly() JsonToken jsonToken = parser.nextToken(); assertEquals(JsonToken.START_OBJECT, jsonToken); - assertEquals(-1, parser.getTokenLocation().getLineNr()); - assertEquals(0, parser.getTokenLocation().getColumnNr()); - assertEquals(-1, parser.getCurrentLocation().getLineNr()); - assertEquals(1, parser.getCurrentLocation().getColumnNr()); + assertEquals(-1, parser.currentTokenLocation().getLineNr()); + assertEquals(0, parser.currentTokenLocation().getColumnNr()); + assertEquals(-1, parser.currentLocation().getLineNr()); + assertEquals(1, parser.currentLocation().getColumnNr()); jsonToken = parser.nextToken(); assertEquals(JsonToken.FIELD_NAME, jsonToken); - assertEquals("zero", parser.getCurrentName()); - assertEquals(1, parser.getTokenLocation().getColumnNr()); - assertEquals(6, parser.getCurrentLocation().getColumnNr()); + assertEquals("zero", parser.currentName()); + assertEquals(1, parser.currentTokenLocation().getColumnNr()); + assertEquals(6, parser.currentLocation().getColumnNr()); jsonToken = parser.nextToken(); assertEquals(JsonToken.VALUE_NUMBER_INT, jsonToken); assertEquals(0, parser.getIntValue()); - assertEquals(6, parser.getTokenLocation().getColumnNr()); - assertEquals(7, parser.getCurrentLocation().getColumnNr()); + assertEquals(6, parser.currentTokenLocation().getColumnNr()); + assertEquals(7, parser.currentLocation().getColumnNr()); jsonToken = parser.nextToken(); assertEquals(JsonToken.FIELD_NAME, jsonToken); - assertEquals("one", parser.getCurrentName()); - assertEquals(7, parser.getTokenLocation().getColumnNr()); - assertEquals(11, parser.getCurrentLocation().getColumnNr()); + assertEquals("one", parser.currentName()); + assertEquals(7, parser.currentTokenLocation().getColumnNr()); + assertEquals(11, parser.currentLocation().getColumnNr()); parser.overrideCurrentName("two"); - assertEquals("two", parser.getCurrentName()); + assertEquals("two", parser.currentName()); jsonToken = parser.nextToken(); assertEquals(JsonToken.VALUE_NUMBER_FLOAT, jsonToken); assertEquals(1.0f, parser.getIntValue(), 0.001f); - assertEquals(11, parser.getTokenLocation().getColumnNr()); - assertEquals(16, parser.getCurrentLocation().getColumnNr()); + assertEquals(11, parser.currentTokenLocation().getColumnNr()); + assertEquals(16, parser.currentLocation().getColumnNr()); jsonToken = parser.nextToken(); assertEquals(JsonToken.END_OBJECT, jsonToken); - assertEquals(-1, parser.getTokenLocation().getLineNr()); - assertEquals(16, parser.getTokenLocation().getColumnNr()); - assertEquals(-1, parser.getCurrentLocation().getLineNr()); - assertEquals(16, parser.getCurrentLocation().getColumnNr()); + assertEquals(-1, parser.currentTokenLocation().getLineNr()); + assertEquals(16, parser.currentTokenLocation().getColumnNr()); + assertEquals(-1, parser.currentLocation().getLineNr()); + assertEquals(16, parser.currentLocation().getColumnNr()); parser.close(); parser.close(); // Intentional From 34c1d590ad1cbebd234415de6f01460ee03aa5cb Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Mon, 25 Aug 2025 20:10:06 +0200 Subject: [PATCH 21/43] Update sbt, scripted-plugin to 1.11.4 (#910) --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index 138bc7a5..aced3065 100755 --- a/project/build.properties +++ b/project/build.properties @@ -1,2 +1,2 @@ -sbt.version=1.11.3 +sbt.version=1.11.4 From d8d81aa32c3ac92849291c14bd1000b2fc6bb275 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Aug 2025 11:10:15 -0700 Subject: [PATCH 22/43] Bump actions/checkout from 4 to 5 (#909) Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/CI.yml | 6 +++--- .github/workflows/release.yml | 2 +- .github/workflows/snapshot.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 4c49c411..a61fb3fa 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -15,7 +15,7 @@ jobs: docs: ${{ steps.changes.outputs.docs }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - uses: dorny/paths-filter@v3 id: changes with: @@ -39,7 +39,7 @@ jobs: needs: changes if: ${{ needs.changes.outputs.code == 'true' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: jcheckstyle run: ./sbt jcheckStyle - name: scalafmtCheckAll @@ -54,7 +54,7 @@ jobs: matrix: java: ['8', '11', '17', '21', '24'] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: actions/setup-java@v4 with: distribution: 'zulu' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c3dca7c2..6d1aa99f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ jobs: name: Release runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 10000 # Fetch all tags so that sbt-dynver can find the previous release version diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 4cc85866..eac8cfbb 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -16,7 +16,7 @@ jobs: name: Publish snapshots runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 10000 # Fetch all tags so that sbt-dynver can find the previous release version From 75482c5aec6bfafad7e17ce4e75c7abff682eec8 Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Mon, 25 Aug 2025 20:10:50 +0200 Subject: [PATCH 23/43] Update airframe-json, airspec to 2025.1.16 (#912) --- build.sbt | 184 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 107 insertions(+), 77 deletions(-) diff --git a/build.sbt b/build.sbt index 135145fd..547e1ebe 100644 --- a/build.sbt +++ b/build.sbt @@ -1,11 +1,9 @@ Global / onChangedBuildSource := ReloadOnSourceChanges // For performance testing, ensure each test run one-by-one -Global / concurrentRestrictions := Seq( - Tags.limit(Tags.Test, 1) -) +Global / concurrentRestrictions := Seq(Tags.limit(Tags.Test, 1)) -val AIRFRAME_VERSION = "2025.1.14" +val AIRFRAME_VERSION = "2025.1.16" // Use dynamic snapshot version strings for non tagged versions ThisBuild / dynverSonatypeSnapshots := true @@ -15,37 +13,65 @@ ThisBuild / dynverSeparator := "-" // Publishing metadata ThisBuild / homepage := Some(url("https://msgpack.org/")) ThisBuild / licenses := Seq("Apache-2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0.txt")) -ThisBuild / scmInfo := Some( - ScmInfo( - url("https://github.com/msgpack/msgpack-java"), - "scm:git@github.com:msgpack/msgpack-java.git" +ThisBuild / scmInfo := + Some( + ScmInfo( + url("https://github.com/msgpack/msgpack-java"), + "scm:git@github.com:msgpack/msgpack-java.git" + ) ) -) -ThisBuild / developers := List( - Developer(id = "frsyuki", name = "Sadayuki Furuhashi", email = "frsyuki@users.sourceforge.jp", url = url("https://github.com/frsyuki")), - Developer(id = "muga", name = "Muga Nishizawa", email = "muga.nishizawa@gmail.com", url = url("https://github.com/muga")), - Developer(id = "oza", name = "Tsuyoshi Ozawa", email = "ozawa.tsuyoshi@gmail.com", url = url("https://github.com/oza")), - Developer(id = "komamitsu", name = "Mitsunori Komatsu", email = "komamitsu@gmail.com", url = url("https://github.com/komamitsu")), - Developer(id = "xerial", name = "Taro L. Saito", email = "leo@xerial.org", url = url("https://github.com/xerial")) -) +ThisBuild / developers := + List( + Developer( + id = "frsyuki", + name = "Sadayuki Furuhashi", + email = "frsyuki@users.sourceforge.jp", + url = url("https://github.com/frsyuki") + ), + Developer( + id = "muga", + name = "Muga Nishizawa", + email = "muga.nishizawa@gmail.com", + url = url("https://github.com/muga") + ), + Developer( + id = "oza", + name = "Tsuyoshi Ozawa", + email = "ozawa.tsuyoshi@gmail.com", + url = url("https://github.com/oza") + ), + Developer( + id = "komamitsu", + name = "Mitsunori Komatsu", + email = "komamitsu@gmail.com", + url = url("https://github.com/komamitsu") + ), + Developer( + id = "xerial", + name = "Taro L. Saito", + email = "leo@xerial.org", + url = url("https://github.com/xerial") + ) + ) -val buildSettings = Seq[Setting[_]]( - organization := "org.msgpack", - organizationName := "MessagePack", +val buildSettings = Seq[Setting[?]]( + organization := "org.msgpack", + organizationName := "MessagePack", organizationHomepage := Some(url("http://msgpack.org/")), - description := "MessagePack for Java", - scalaVersion := "3.7.1", - Test / logBuffered := false, + description := "MessagePack for Java", + scalaVersion := "3.7.1", + Test / logBuffered := false, // msgpack-java should be a pure-java library, so remove Scala specific configurations - autoScalaLibrary := false, - crossPaths := false, + autoScalaLibrary := false, + crossPaths := false, publishMavenStyle := true, // JVM options for building scalacOptions ++= Seq("-encoding", "UTF-8", "-deprecation", "-unchecked", "-feature"), Test / javaOptions ++= Seq("-ea"), javacOptions ++= Seq("-source", "1.8", "-target", "1.8"), - Compile / compile / javacOptions ++= Seq("-encoding", "UTF-8", "-Xlint:unchecked", "-Xlint:deprecation"), + Compile / compile / javacOptions ++= + Seq("-encoding", "UTF-8", "-Xlint:unchecked", "-Xlint:deprecation"), // Use lenient validation mode when generating Javadoc (for Java8) doc / javacOptions := { val opts = Seq("-source", "1.8") @@ -58,17 +84,21 @@ val buildSettings = Seq[Setting[_]]( // Add sonatype repository settings publishTo := { val centralSnapshots = "https://central.sonatype.com/repository/maven-snapshots/" - if (isSnapshot.value) Some("central-snapshots" at centralSnapshots) - else localStaging.value + if (isSnapshot.value) + Some("central-snapshots" at centralSnapshots) + else + localStaging.value }, // Style check config: (sbt-jchekcstyle) jcheckStyleConfig := "facebook", // Run jcheckstyle both for main and test codes - Compile / compile := ((Compile / compile) dependsOn (Compile / jcheckStyle)).value, - Test / compile := ((Test / compile) dependsOn (Test / jcheckStyle)).value + Compile / compile := + ((Compile / compile) dependsOn (Compile / jcheckStyle)).value, + Test / compile := + ((Test / compile) dependsOn (Test / jcheckStyle)).value ) -val junitJupiter = "org.junit.jupiter" % "junit-jupiter" % "5.11.4" % "test" +val junitJupiter = "org.junit.jupiter" % "junit-jupiter" % "5.11.4" % "test" val junitVintage = "org.junit.vintage" % "junit-vintage-engine" % "5.11.4" % "test" // Project settings @@ -77,8 +107,8 @@ lazy val root = Project(id = "msgpack-java", base = file(".")) buildSettings, // Do not publish the root project publishArtifact := false, - publish := {}, - publishLocal := {} + publish := {}, + publishLocal := {} ) .aggregate(msgpackCore, msgpackJackson) @@ -86,58 +116,58 @@ lazy val msgpackCore = Project(id = "msgpack-core", base = file("msgpack-core")) .enablePlugins(SbtOsgi) .settings( buildSettings, - description := "Core library of the MessagePack for Java", + description := "Core library of the MessagePack for Java", OsgiKeys.bundleSymbolicName := "org.msgpack.msgpack-core", - OsgiKeys.exportPackage := Seq( - // TODO enumerate used packages automatically - "org.msgpack.core", - "org.msgpack.core.annotations", - "org.msgpack.core.buffer", - "org.msgpack.value", - "org.msgpack.value.impl" - ), + OsgiKeys.exportPackage := + Seq( + // TODO enumerate used packages automatically + "org.msgpack.core", + "org.msgpack.core.annotations", + "org.msgpack.core.buffer", + "org.msgpack.value", + "org.msgpack.value.impl" + ), testFrameworks += new TestFramework("wvlet.airspec.Framework"), - Test / javaOptions ++= Seq( - // --add-opens is not available in JDK8 - "-XX:+IgnoreUnrecognizedVMOptions", - "--add-opens=java.base/java.nio=ALL-UNNAMED", - "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED" - ), + Test / javaOptions ++= + Seq( + // --add-opens is not available in JDK8 + "-XX:+IgnoreUnrecognizedVMOptions", + "--add-opens=java.base/java.nio=ALL-UNNAMED", + "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED" + ), Test / fork := true, - libraryDependencies ++= Seq( - // msgpack-core should have no external dependencies - junitJupiter, - junitVintage, - "org.wvlet.airframe" %% "airframe-json" % AIRFRAME_VERSION % "test", - "org.wvlet.airframe" %% "airspec" % AIRFRAME_VERSION % "test", - // Add property testing support with forAll methods - "org.scalacheck" %% "scalacheck" % "1.18.1" % "test", - // For performance comparison with msgpack v6 - "org.msgpack" % "msgpack" % "0.6.12" % "test", - // For integration test with Akka - "com.typesafe.akka" %% "akka-actor" % "2.6.20" % "test", - "org.scala-lang.modules" %% "scala-collection-compat" % "2.13.0" % "test" - ) + libraryDependencies ++= + Seq( + // msgpack-core should have no external dependencies + junitJupiter, + junitVintage, + "org.wvlet.airframe" %% "airframe-json" % AIRFRAME_VERSION % "test", + "org.wvlet.airframe" %% "airspec" % AIRFRAME_VERSION % "test", + // Add property testing support with forAll methods + "org.scalacheck" %% "scalacheck" % "1.18.1" % "test", + // For performance comparison with msgpack v6 + "org.msgpack" % "msgpack" % "0.6.12" % "test", + // For integration test with Akka + "com.typesafe.akka" %% "akka-actor" % "2.6.20" % "test", + "org.scala-lang.modules" %% "scala-collection-compat" % "2.13.0" % "test" + ) ) -lazy val msgpackJackson = - Project(id = "msgpack-jackson", base = file("msgpack-jackson")) - .enablePlugins(SbtOsgi) - .settings( - buildSettings, - name := "jackson-dataformat-msgpack", - description := "Jackson extension that adds support for MessagePack", - OsgiKeys.bundleSymbolicName := "org.msgpack.msgpack-jackson", - OsgiKeys.exportPackage := Seq( - "org.msgpack.jackson", - "org.msgpack.jackson.dataformat" - ), - libraryDependencies ++= Seq( +lazy val msgpackJackson = Project(id = "msgpack-jackson", base = file("msgpack-jackson")) + .enablePlugins(SbtOsgi) + .settings( + buildSettings, + name := "jackson-dataformat-msgpack", + description := "Jackson extension that adds support for MessagePack", + OsgiKeys.bundleSymbolicName := "org.msgpack.msgpack-jackson", + OsgiKeys.exportPackage := Seq("org.msgpack.jackson", "org.msgpack.jackson.dataformat"), + libraryDependencies ++= + Seq( "com.fasterxml.jackson.core" % "jackson-databind" % "2.18.4", junitJupiter, junitVintage, "org.apache.commons" % "commons-math3" % "3.6.1" % "test" ), - testOptions += Tests.Argument(TestFrameworks.JUnit, "-v") - ) - .dependsOn(msgpackCore) + testOptions += Tests.Argument(TestFrameworks.JUnit, "-v") + ) + .dependsOn(msgpackCore) From 12062270a5ee2a0c754a11cef4b0a03e0f0078e9 Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Mon, 25 Aug 2025 20:11:04 +0200 Subject: [PATCH 24/43] Update scalafmt-core to 3.9.9 (#907) * Update scalafmt-core to 3.9.9 * Reformat with scalafmt 3.9.9 Executed command: scalafmt --non-interactive * Add 'Reformat with scalafmt 3.9.9' to .git-blame-ignore-revs --- .git-blame-ignore-revs | 2 ++ .scalafmt.conf | 2 +- project/plugins.sbt | 8 ++++---- 3 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 00000000..285ed6f4 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +# Scala Steward: Reformat with scalafmt 3.9.9 +424ec59eb4865feb383ca53b4278dfb8b9b6c36c diff --git a/.scalafmt.conf b/.scalafmt.conf index e8563baf..a4b995aa 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = 3.9.8 +version = 3.9.9 project.layout = StandardConvention runner.dialect = scala3 maxColumn = 100 diff --git a/project/plugins.sbt b/project/plugins.sbt index 5bc49937..18f414ea 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,10 +1,10 @@ -addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.1") +addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.1") // TODO: Fixes jacoco error: // java.lang.NoClassDefFoundError: Could not initialize class org.jacoco.core.internal.flow.ClassProbesAdapter //addSbtPlugin("com.github.sbt" % "sbt-jacoco" % "3.3.0") -addSbtPlugin("org.xerial.sbt" % "sbt-jcheckstyle" % "0.2.1") +addSbtPlugin("org.xerial.sbt" % "sbt-jcheckstyle" % "0.2.1") addSbtPlugin("com.github.sbt" % "sbt-osgi" % "0.10.0") -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.5") -addSbtPlugin("com.github.sbt" % "sbt-dynver" % "5.1.1") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.5") +addSbtPlugin("com.github.sbt" % "sbt-dynver" % "5.1.1") scalacOptions ++= Seq("-deprecation", "-feature") From e93fb75eed2d8ca6e41993d4dad3f9c68d33be29 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 30 Aug 2025 18:24:48 -0700 Subject: [PATCH 25/43] Bump actions/setup-java from 4 to 5 (#914) Bumps [actions/setup-java](https://github.com/actions/setup-java) from 4 to 5. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-java dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/CI.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/snapshot.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index a61fb3fa..091ca0de 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -55,7 +55,7 @@ jobs: java: ['8', '11', '17', '21', '24'] steps: - uses: actions/checkout@v5 - - uses: actions/setup-java@v4 + - uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: ${{ matrix.java }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6d1aa99f..16adf80f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,7 @@ jobs: # Fetch all tags so that sbt-dynver can find the previous release version - run: git fetch --tags -f # Install OpenJDK 8 - - uses: actions/setup-java@v4 + - uses: actions/setup-java@v5 with: # We need to use JDK8 for Android compatibility https://github.com/msgpack/msgpack-java/issues/516 java-version: 8 diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index eac8cfbb..749e6175 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -21,7 +21,7 @@ jobs: fetch-depth: 10000 # Fetch all tags so that sbt-dynver can find the previous release version - run: git fetch --tags - - uses: actions/setup-java@v4 + - uses: actions/setup-java@v5 with: java-version: 11 distribution: adopt From be6f0160119eb1214449e7b8470c162df39193dc Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Sun, 31 Aug 2025 03:24:57 +0200 Subject: [PATCH 26/43] Update sbt, scripted-plugin to 1.11.5 (#913) --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index aced3065..d05ee025 100755 --- a/project/build.properties +++ b/project/build.properties @@ -1,2 +1,2 @@ -sbt.version=1.11.4 +sbt.version=1.11.5 From cab44596bf6ebe3b74198897cc77e5e7ed91bccb Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Mon, 1 Sep 2025 23:16:30 +0200 Subject: [PATCH 27/43] Update junit-jupiter to 5.13.4 (#905) --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 547e1ebe..143ef7e1 100644 --- a/build.sbt +++ b/build.sbt @@ -98,7 +98,7 @@ val buildSettings = Seq[Setting[?]]( ((Test / compile) dependsOn (Test / jcheckStyle)).value ) -val junitJupiter = "org.junit.jupiter" % "junit-jupiter" % "5.11.4" % "test" +val junitJupiter = "org.junit.jupiter" % "junit-jupiter" % "5.13.4" % "test" val junitVintage = "org.junit.vintage" % "junit-vintage-engine" % "5.11.4" % "test" // Project settings From 17dc837745ef3be60aa3f37b44230ce92fffd5e4 Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Thu, 18 Sep 2025 17:18:08 +0200 Subject: [PATCH 28/43] Update sbt, scripted-plugin to 1.11.6 (#918) --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index d05ee025..73840fdd 100755 --- a/project/build.properties +++ b/project/build.properties @@ -1,2 +1,2 @@ -sbt.version=1.11.5 +sbt.version=1.11.6 From 06cf66d77ba85ef4ad76e7a65da4b6d6b2672bbd Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Thu, 18 Sep 2025 17:18:17 +0200 Subject: [PATCH 29/43] Update airframe-json, airspec to 2025.1.18 (#920) --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 143ef7e1..5e89ef1e 100644 --- a/build.sbt +++ b/build.sbt @@ -3,7 +3,7 @@ Global / onChangedBuildSource := ReloadOnSourceChanges // For performance testing, ensure each test run one-by-one Global / concurrentRestrictions := Seq(Tags.limit(Tags.Test, 1)) -val AIRFRAME_VERSION = "2025.1.16" +val AIRFRAME_VERSION = "2025.1.18" // Use dynamic snapshot version strings for non tagged versions ThisBuild / dynverSonatypeSnapshots := true From 918a396fcde16987abc8a26edb126248c868c9aa Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Thu, 18 Sep 2025 17:18:36 +0200 Subject: [PATCH 30/43] Update scalacheck to 1.19.0 (#919) --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 5e89ef1e..3f8c9813 100644 --- a/build.sbt +++ b/build.sbt @@ -144,7 +144,7 @@ lazy val msgpackCore = Project(id = "msgpack-core", base = file("msgpack-core")) "org.wvlet.airframe" %% "airframe-json" % AIRFRAME_VERSION % "test", "org.wvlet.airframe" %% "airspec" % AIRFRAME_VERSION % "test", // Add property testing support with forAll methods - "org.scalacheck" %% "scalacheck" % "1.18.1" % "test", + "org.scalacheck" %% "scalacheck" % "1.19.0" % "test", // For performance comparison with msgpack v6 "org.msgpack" % "msgpack" % "0.6.12" % "test", // For integration test with Akka From a7a54ea6ed5710391f6f4222189690b0cc630103 Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Mon, 24 Nov 2025 19:47:13 +0100 Subject: [PATCH 31/43] Update sbt-scalafmt to 2.5.6 (#932) --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index 18f414ea..a7594c7a 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -4,7 +4,7 @@ addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.1") //addSbtPlugin("com.github.sbt" % "sbt-jacoco" % "3.3.0") addSbtPlugin("org.xerial.sbt" % "sbt-jcheckstyle" % "0.2.1") addSbtPlugin("com.github.sbt" % "sbt-osgi" % "0.10.0") -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.5") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.6") addSbtPlugin("com.github.sbt" % "sbt-dynver" % "5.1.1") scalacOptions ++= Seq("-deprecation", "-feature") From 78e5b7e2cb3d50e86e276e771e5fc9f794f8240f Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Mon, 24 Nov 2025 19:47:24 +0100 Subject: [PATCH 32/43] Update airframe-json, airspec to 2025.1.21 (#929) --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 3f8c9813..6e3d753d 100644 --- a/build.sbt +++ b/build.sbt @@ -3,7 +3,7 @@ Global / onChangedBuildSource := ReloadOnSourceChanges // For performance testing, ensure each test run one-by-one Global / concurrentRestrictions := Seq(Tags.limit(Tags.Test, 1)) -val AIRFRAME_VERSION = "2025.1.18" +val AIRFRAME_VERSION = "2025.1.21" // Use dynamic snapshot version strings for non tagged versions ThisBuild / dynverSonatypeSnapshots := true From bfa9fd4674a3f7e92922debbf1cc04c3670243c9 Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Mon, 24 Nov 2025 19:48:12 +0100 Subject: [PATCH 33/43] Update scala-collection-compat to 2.14.0 (#926) --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 6e3d753d..d70268a0 100644 --- a/build.sbt +++ b/build.sbt @@ -149,7 +149,7 @@ lazy val msgpackCore = Project(id = "msgpack-core", base = file("msgpack-core")) "org.msgpack" % "msgpack" % "0.6.12" % "test", // For integration test with Akka "com.typesafe.akka" %% "akka-actor" % "2.6.20" % "test", - "org.scala-lang.modules" %% "scala-collection-compat" % "2.13.0" % "test" + "org.scala-lang.modules" %% "scala-collection-compat" % "2.14.0" % "test" ) ) From f6427b4aa757aba58fd6f9788a3db0b789342e52 Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Mon, 24 Nov 2025 19:48:23 +0100 Subject: [PATCH 34/43] Update sbt, scripted-plugin to 1.11.7 (#925) --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index 73840fdd..b1b10405 100755 --- a/project/build.properties +++ b/project/build.properties @@ -1,2 +1,2 @@ -sbt.version=1.11.6 +sbt.version=1.11.7 From 81a9f0d80c81a24229a2641075a9e802c0843ec2 Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Mon, 24 Nov 2025 19:49:33 +0100 Subject: [PATCH 35/43] Update junit-jupiter to 5.14.1 (#930) --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index d70268a0..f8600c56 100644 --- a/build.sbt +++ b/build.sbt @@ -98,7 +98,7 @@ val buildSettings = Seq[Setting[?]]( ((Test / compile) dependsOn (Test / jcheckStyle)).value ) -val junitJupiter = "org.junit.jupiter" % "junit-jupiter" % "5.13.4" % "test" +val junitJupiter = "org.junit.jupiter" % "junit-jupiter" % "5.14.1" % "test" val junitVintage = "org.junit.vintage" % "junit-vintage-engine" % "5.11.4" % "test" // Project settings From 9c27ee586204993dbb6348024f72405945c82108 Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Fri, 2 Jan 2026 18:29:33 +0100 Subject: [PATCH 36/43] Update airframe-json, airspec to 2025.1.22 (#938) --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index f8600c56..43536584 100644 --- a/build.sbt +++ b/build.sbt @@ -3,7 +3,7 @@ Global / onChangedBuildSource := ReloadOnSourceChanges // For performance testing, ensure each test run one-by-one Global / concurrentRestrictions := Seq(Tags.limit(Tags.Test, 1)) -val AIRFRAME_VERSION = "2025.1.21" +val AIRFRAME_VERSION = "2025.1.22" // Use dynamic snapshot version strings for non tagged versions ThisBuild / dynverSonatypeSnapshots := true From c9864c5e08ff34acb1831e42b63ac558ef86c670 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Jan 2026 09:29:42 -0800 Subject: [PATCH 37/43] Bump actions/cache from 4 to 5 (#937) Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/cache dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 091ca0de..86936f65 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -59,7 +59,7 @@ jobs: with: distribution: 'zulu' java-version: ${{ matrix.java }} - - uses: actions/cache@v4 + - uses: actions/cache@v5 with: path: ~/.cache key: ${{ runner.os }}-jdk${{ matrix.java }}-${{ hashFiles('**/*.sbt') }} From 56e7bc6879b2d2184896c13046ba7ea61528ae8f Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Fri, 2 Jan 2026 18:29:53 +0100 Subject: [PATCH 38/43] Update junit-vintage-engine to 5.14.1 (#931) --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 43536584..4d72279e 100644 --- a/build.sbt +++ b/build.sbt @@ -99,7 +99,7 @@ val buildSettings = Seq[Setting[?]]( ) val junitJupiter = "org.junit.jupiter" % "junit-jupiter" % "5.14.1" % "test" -val junitVintage = "org.junit.vintage" % "junit-vintage-engine" % "5.11.4" % "test" +val junitVintage = "org.junit.vintage" % "junit-vintage-engine" % "5.14.1" % "test" // Project settings lazy val root = Project(id = "msgpack-java", base = file(".")) From befe3b943fbdc59070acfea8feb317044096bc85 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Jan 2026 09:30:03 -0800 Subject: [PATCH 39/43] Bump actions/checkout from 5 to 6 (#935) Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/CI.yml | 6 +++--- .github/workflows/release.yml | 2 +- .github/workflows/snapshot.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 86936f65..a427ec6f 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -15,7 +15,7 @@ jobs: docs: ${{ steps.changes.outputs.docs }} steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - uses: dorny/paths-filter@v3 id: changes with: @@ -39,7 +39,7 @@ jobs: needs: changes if: ${{ needs.changes.outputs.code == 'true' }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: jcheckstyle run: ./sbt jcheckStyle - name: scalafmtCheckAll @@ -54,7 +54,7 @@ jobs: matrix: java: ['8', '11', '17', '21', '24'] steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-java@v5 with: distribution: 'zulu' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 16adf80f..0cec5029 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ jobs: name: Release runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: fetch-depth: 10000 # Fetch all tags so that sbt-dynver can find the previous release version diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 749e6175..dc0fac1d 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -16,7 +16,7 @@ jobs: name: Publish snapshots runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: fetch-depth: 10000 # Fetch all tags so that sbt-dynver can find the previous release version From daa2ea6b2f11f500e22c70a22f689f7a9debdeae Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Fri, 2 Jan 2026 10:26:44 -0800 Subject: [PATCH 40/43] Merge commit from fork MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve readPayload(int) to use gradual memory allocation for large payloads (>64MB). This validates that sufficient data is available before completing allocation, improving robustness when handling untrusted input. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 --- .../org/msgpack/core/MessageUnpacker.java | 85 ++++++++++++- .../msgpack/core/PayloadSizeLimitTest.scala | 116 ++++++++++++++++++ 2 files changed, 197 insertions(+), 4 deletions(-) create mode 100644 msgpack-core/src/test/scala/org/msgpack/core/PayloadSizeLimitTest.scala diff --git a/msgpack-core/src/main/java/org/msgpack/core/MessageUnpacker.java b/msgpack-core/src/main/java/org/msgpack/core/MessageUnpacker.java index 5a9a1a63..5819f6c2 100644 --- a/msgpack-core/src/main/java/org/msgpack/core/MessageUnpacker.java +++ b/msgpack-core/src/main/java/org/msgpack/core/MessageUnpacker.java @@ -26,6 +26,8 @@ import java.io.Closeable; import java.io.IOException; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; @@ -150,6 +152,14 @@ public class MessageUnpacker { private static final MessageBuffer EMPTY_BUFFER = MessageBuffer.wrap(new byte[0]); + /** + * Threshold for switching from upfront allocation to gradual allocation. + * Payloads up to this size use efficient upfront allocation. + * Payloads exceeding this size use gradual allocation to detect malicious files + * that declare large payload sizes but contain little actual data. + */ + private static final int GRADUAL_ALLOCATION_THRESHOLD = 64 * 1024 * 1024; // 64 MB + private final boolean allowReadingStringAsBinary; private final boolean allowReadingBinaryAsString; private final CodingErrorAction actionOnMalformedString; @@ -1637,18 +1647,85 @@ public void readPayload(byte[] dst) * This method allocates a new byte array and consumes specified amount of bytes into the byte array. * *

- * This method is equivalent to readPayload(new byte[length]). + * For sizes up to {@link #GRADUAL_ALLOCATION_THRESHOLD}, this method uses efficient upfront allocation. + * For larger sizes, it uses gradual allocation to protect against malicious files that declare + * large payload sizes but contain little actual data. * * @param length number of bytes to be read * @return the new byte array * @throws IOException when underlying input throws IOException + * @throws MessageSizeException when the input ends before the declared size is reached (for large payloads) */ public byte[] readPayload(int length) throws IOException { - byte[] newArray = new byte[length]; - readPayload(newArray); - return newArray; + if (length <= GRADUAL_ALLOCATION_THRESHOLD) { + // Small/moderate size: use efficient upfront allocation + byte[] newArray = new byte[length]; + readPayload(newArray); + return newArray; + } + + // Large declared size: use gradual allocation to protect against malicious files + return readPayloadGradually(length); + } + + /** + * Read payload gradually, allocating memory only as data becomes available. + * This method protects against malicious files that declare large payload sizes + * but contain little actual data. + * + * @param declaredLength the declared payload length + * @return the payload bytes + * @throws IOException when underlying input throws IOException + * @throws MessageSizeException when the input ends before the declared size is reached + */ + private byte[] readPayloadGradually(int declaredLength) + throws IOException + { + List chunks = new ArrayList<>(); + int totalRead = 0; + int remaining = declaredLength; + + while (remaining > 0) { + int bufferRemaining = buffer.size() - position; + if (bufferRemaining == 0) { + // Need more data from input + MessageBuffer next = in.next(); + if (next == null) { + // Input ended before we read the declared size + throw new MessageSizeException( + String.format("Payload declared %,d bytes but input ended after %,d bytes", + declaredLength, totalRead), + declaredLength); + } + totalReadBytes += buffer.size(); + buffer = next; + position = 0; + bufferRemaining = buffer.size(); + } + + int toRead = Math.min(remaining, bufferRemaining); + byte[] chunk = new byte[toRead]; + buffer.getBytes(position, chunk, 0, toRead); + chunks.add(chunk); + totalRead += toRead; + position += toRead; + remaining -= toRead; + } + + // All data verified to exist - combine chunks into result + if (chunks.size() == 1) { + return chunks.get(0); // Common case: single chunk, no copy needed + } + + byte[] result = new byte[declaredLength]; + int offset = 0; + for (byte[] chunk : chunks) { + System.arraycopy(chunk, 0, result, offset, chunk.length); + offset += chunk.length; + } + return result; } /** diff --git a/msgpack-core/src/test/scala/org/msgpack/core/PayloadSizeLimitTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/PayloadSizeLimitTest.scala new file mode 100644 index 00000000..e42c38a5 --- /dev/null +++ b/msgpack-core/src/test/scala/org/msgpack/core/PayloadSizeLimitTest.scala @@ -0,0 +1,116 @@ +package org.msgpack.core + +import wvlet.airspec.AirSpec + +import java.nio.ByteBuffer + +class PayloadSizeLimitTest extends AirSpec: + + test("detects malicious EXT32 file with huge declared size but tiny actual data") { + // Craft a malicious EXT32 header: + // 0xC9 = EXT32 format + // 4 bytes = declared length (100MB, which exceeds 64MB threshold) + // 1 byte = extension type + // followed by only 1 byte of actual data (not 100MB) + val declaredLength = 100 * 1024 * 1024 // 100 MB + val buffer = ByteBuffer.allocate(7) // header(1) + length(4) + type(1) + data(1) + buffer.put(0xC9.toByte) // EXT32 format code + buffer.putInt(declaredLength) // declared length (big-endian) + buffer.put(0x01.toByte) // extension type + buffer.put(0x41.toByte) // only 1 byte of actual data + val maliciousData = buffer.array() + + val unpacker = MessagePack.newDefaultUnpacker(maliciousData) + + // Should throw MessageSizeException because the declared size exceeds actual data + intercept[MessageSizeException] { + unpacker.unpackValue() + } + } + + test("detects malicious BIN32 file with huge declared size but tiny actual data") { + // Craft a malicious BIN32 header: + // 0xC6 = BIN32 format + // 4 bytes = declared length (100MB, which exceeds 64MB threshold) + // followed by only 1 byte of actual data (not 100MB) + val declaredLength = 100 * 1024 * 1024 // 100 MB + val buffer = ByteBuffer.allocate(6) // header(1) + length(4) + data(1) + buffer.put(0xC6.toByte) // BIN32 format code + buffer.putInt(declaredLength) // declared length (big-endian) + buffer.put(0x41.toByte) // only 1 byte of actual data + val maliciousData = buffer.array() + + val unpacker = MessagePack.newDefaultUnpacker(maliciousData) + + // Should throw MessageSizeException because the declared size exceeds actual data + intercept[MessageSizeException] { + unpacker.unpackValue() + } + } + + test("legitimate extension data works correctly") { + val packer = MessagePack.newDefaultBufferPacker() + val testData = Array.fill[Byte](1000)(0x42) + packer.packExtensionTypeHeader(0x01.toByte, testData.length) + packer.writePayload(testData) + val msgpack = packer.toByteArray + + val unpacker = MessagePack.newDefaultUnpacker(msgpack) + val value = unpacker.unpackValue() + + assert(value.isExtensionValue) + assert(value.asExtensionValue().getData.length == 1000) + } + + test("legitimate binary data works correctly") { + val packer = MessagePack.newDefaultBufferPacker() + val testData = Array.fill[Byte](1000)(0x42) + packer.packBinaryHeader(testData.length) + packer.writePayload(testData) + val msgpack = packer.toByteArray + + val unpacker = MessagePack.newDefaultUnpacker(msgpack) + val value = unpacker.unpackValue() + + assert(value.isBinaryValue) + assert(value.asBinaryValue().asByteArray().length == 1000) + } + + test("readPayload directly with malicious size throws exception") { + // Test readPayload(int) directly with a malicious input + val declaredLength = 100 * 1024 * 1024 // 100 MB + val buffer = ByteBuffer.allocate(6) // header(1) + length(4) + data(1) + buffer.put(0xC6.toByte) // BIN32 format code + buffer.putInt(declaredLength) // declared length (big-endian) + buffer.put(0x41.toByte) // only 1 byte of actual data + val maliciousData = buffer.array() + + val unpacker = MessagePack.newDefaultUnpacker(maliciousData) + + // First, unpack the binary header to get the declared length + val len = unpacker.unpackBinaryHeader() + assert(len == declaredLength) + + // Then try to read the payload - should throw exception + intercept[MessageSizeException] { + unpacker.readPayload(len) + } + } + + test("small payloads under threshold work with upfront allocation") { + // Payloads under 64MB should use the efficient upfront allocation path + val packer = MessagePack.newDefaultBufferPacker() + val testData = Array.fill[Byte](10000)(0x42) // 10KB, well under threshold + packer.packBinaryHeader(testData.length) + packer.writePayload(testData) + val msgpack = packer.toByteArray + + val unpacker = MessagePack.newDefaultUnpacker(msgpack) + val len = unpacker.unpackBinaryHeader() + val payload = unpacker.readPayload(len) + + assert(payload.length == 10000) + assert(payload.forall(_ == 0x42.toByte)) + } + +end PayloadSizeLimitTest From 884e9c1baec57c211253cd92fd8f81c4c899f943 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Fri, 2 Jan 2026 10:32:18 -0800 Subject: [PATCH 41/43] Fix Scala code formatting (#939) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix Scala code formatting in PayloadSizeLimitTest Apply scalafmt to align variable declarations and comments according to project style guidelines. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 --- .../msgpack/core/PayloadSizeLimitTest.scala | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/msgpack-core/src/test/scala/org/msgpack/core/PayloadSizeLimitTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/PayloadSizeLimitTest.scala index e42c38a5..7f454c85 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/PayloadSizeLimitTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/PayloadSizeLimitTest.scala @@ -12,13 +12,13 @@ class PayloadSizeLimitTest extends AirSpec: // 4 bytes = declared length (100MB, which exceeds 64MB threshold) // 1 byte = extension type // followed by only 1 byte of actual data (not 100MB) - val declaredLength = 100 * 1024 * 1024 // 100 MB - val buffer = ByteBuffer.allocate(7) // header(1) + length(4) + type(1) + data(1) - buffer.put(0xC9.toByte) // EXT32 format code - buffer.putInt(declaredLength) // declared length (big-endian) - buffer.put(0x01.toByte) // extension type - buffer.put(0x41.toByte) // only 1 byte of actual data - val maliciousData = buffer.array() + val declaredLength = 100 * 1024 * 1024 // 100 MB + val buffer = ByteBuffer.allocate(7) // header(1) + length(4) + type(1) + data(1) + buffer.put(0xc9.toByte) // EXT32 format code + buffer.putInt(declaredLength) // declared length (big-endian) + buffer.put(0x01.toByte) // extension type + buffer.put(0x41.toByte) // only 1 byte of actual data + val maliciousData = buffer.array() val unpacker = MessagePack.newDefaultUnpacker(maliciousData) @@ -33,12 +33,12 @@ class PayloadSizeLimitTest extends AirSpec: // 0xC6 = BIN32 format // 4 bytes = declared length (100MB, which exceeds 64MB threshold) // followed by only 1 byte of actual data (not 100MB) - val declaredLength = 100 * 1024 * 1024 // 100 MB - val buffer = ByteBuffer.allocate(6) // header(1) + length(4) + data(1) - buffer.put(0xC6.toByte) // BIN32 format code - buffer.putInt(declaredLength) // declared length (big-endian) - buffer.put(0x41.toByte) // only 1 byte of actual data - val maliciousData = buffer.array() + val declaredLength = 100 * 1024 * 1024 // 100 MB + val buffer = ByteBuffer.allocate(6) // header(1) + length(4) + data(1) + buffer.put(0xc6.toByte) // BIN32 format code + buffer.putInt(declaredLength) // declared length (big-endian) + buffer.put(0x41.toByte) // only 1 byte of actual data + val maliciousData = buffer.array() val unpacker = MessagePack.newDefaultUnpacker(maliciousData) @@ -49,28 +49,28 @@ class PayloadSizeLimitTest extends AirSpec: } test("legitimate extension data works correctly") { - val packer = MessagePack.newDefaultBufferPacker() + val packer = MessagePack.newDefaultBufferPacker() val testData = Array.fill[Byte](1000)(0x42) packer.packExtensionTypeHeader(0x01.toByte, testData.length) packer.writePayload(testData) val msgpack = packer.toByteArray val unpacker = MessagePack.newDefaultUnpacker(msgpack) - val value = unpacker.unpackValue() + val value = unpacker.unpackValue() assert(value.isExtensionValue) assert(value.asExtensionValue().getData.length == 1000) } test("legitimate binary data works correctly") { - val packer = MessagePack.newDefaultBufferPacker() + val packer = MessagePack.newDefaultBufferPacker() val testData = Array.fill[Byte](1000)(0x42) packer.packBinaryHeader(testData.length) packer.writePayload(testData) val msgpack = packer.toByteArray val unpacker = MessagePack.newDefaultUnpacker(msgpack) - val value = unpacker.unpackValue() + val value = unpacker.unpackValue() assert(value.isBinaryValue) assert(value.asBinaryValue().asByteArray().length == 1000) @@ -78,12 +78,12 @@ class PayloadSizeLimitTest extends AirSpec: test("readPayload directly with malicious size throws exception") { // Test readPayload(int) directly with a malicious input - val declaredLength = 100 * 1024 * 1024 // 100 MB - val buffer = ByteBuffer.allocate(6) // header(1) + length(4) + data(1) - buffer.put(0xC6.toByte) // BIN32 format code - buffer.putInt(declaredLength) // declared length (big-endian) - buffer.put(0x41.toByte) // only 1 byte of actual data - val maliciousData = buffer.array() + val declaredLength = 100 * 1024 * 1024 // 100 MB + val buffer = ByteBuffer.allocate(6) // header(1) + length(4) + data(1) + buffer.put(0xc6.toByte) // BIN32 format code + buffer.putInt(declaredLength) // declared length (big-endian) + buffer.put(0x41.toByte) // only 1 byte of actual data + val maliciousData = buffer.array() val unpacker = MessagePack.newDefaultUnpacker(maliciousData) @@ -99,15 +99,15 @@ class PayloadSizeLimitTest extends AirSpec: test("small payloads under threshold work with upfront allocation") { // Payloads under 64MB should use the efficient upfront allocation path - val packer = MessagePack.newDefaultBufferPacker() - val testData = Array.fill[Byte](10000)(0x42) // 10KB, well under threshold + val packer = MessagePack.newDefaultBufferPacker() + val testData = Array.fill[Byte](10000)(0x42) // 10KB, well under threshold packer.packBinaryHeader(testData.length) packer.writePayload(testData) val msgpack = packer.toByteArray val unpacker = MessagePack.newDefaultUnpacker(msgpack) - val len = unpacker.unpackBinaryHeader() - val payload = unpacker.readPayload(len) + val len = unpacker.unpackBinaryHeader() + val payload = unpacker.readPayload(len) assert(payload.length == 10000) assert(payload.forall(_ == 0x42.toByte)) From ab5dc83f7039a3fe009d84d39e8b5f83addb5a45 Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Fri, 2 Jan 2026 20:44:35 +0100 Subject: [PATCH 42/43] Update scalafmt-core to 3.9.10 (#921) --- .scalafmt.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index a4b995aa..8ef32eb0 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = 3.9.9 +version = 3.9.10 project.layout = StandardConvention runner.dialect = scala3 maxColumn = 100 From 580fde4766e6e6a6931cabf6062a6661377185da Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Mon, 5 Jan 2026 18:36:02 +0100 Subject: [PATCH 43/43] Update scalafmt-core to 3.10.3 (#941) * Update scalafmt-core to 3.10.3 * Reformat with scalafmt 3.10.3 Executed command: scalafmt --non-interactive * Add 'Reformat with scalafmt 3.10.3' to .git-blame-ignore-revs --- .git-blame-ignore-revs | 3 +++ .scalafmt.conf | 2 +- .../scala/org/msgpack/core/MessagePackSpec.scala | 3 ++- .../scala/org/msgpack/core/MessagePackTest.scala | 13 +++++++++---- .../scala/org/msgpack/core/MessagePackerTest.scala | 8 ++++++-- .../org/msgpack/core/MessageUnpackerTest.scala | 7 ++++--- .../core/buffer/MessageBufferInputTest.scala | 10 +++++++--- .../scala/org/msgpack/value/ValueTypeTest.scala | 3 ++- .../test/scala/org/msgpack/value/VariableTest.scala | 4 +++- 9 files changed, 37 insertions(+), 16 deletions(-) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 285ed6f4..aead1172 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,2 +1,5 @@ # Scala Steward: Reformat with scalafmt 3.9.9 424ec59eb4865feb383ca53b4278dfb8b9b6c36c + +# Scala Steward: Reformat with scalafmt 3.10.3 +d8af028d2cd271ab7f3adec9842f07cce86a2ac3 diff --git a/.scalafmt.conf b/.scalafmt.conf index 8ef32eb0..d30b0537 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = 3.9.10 +version = 3.10.3 project.layout = StandardConvention runner.dialect = scala3 maxColumn = 100 diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackSpec.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackSpec.scala index 135c4921..21080f65 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackSpec.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackSpec.scala @@ -16,7 +16,8 @@ package org.msgpack.core import wvlet.log.LogLevel -import wvlet.log.io.{TimeReport, Timer} +import wvlet.log.io.TimeReport +import wvlet.log.io.Timer import java.io.ByteArrayOutputStream diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala index b5541393..16236c65 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala @@ -15,18 +15,23 @@ // package org.msgpack.core -import org.msgpack.core.MessagePack.{Code, PackerConfig, UnpackerConfig} +import org.msgpack.core.MessagePack.Code +import org.msgpack.core.MessagePack.PackerConfig +import org.msgpack.core.MessagePack.UnpackerConfig import org.msgpack.core.MessagePackSpec.toHex -import org.msgpack.value.{Value, Variable} +import org.msgpack.value.Value +import org.msgpack.value.Variable import org.scalacheck.Prop.propBoolean -import org.scalacheck.{Arbitrary, Gen} +import org.scalacheck.Arbitrary +import org.scalacheck.Gen import wvlet.airspec.AirSpec import wvlet.airspec.spi.PropertyCheck import java.io.ByteArrayOutputStream import java.math.BigInteger import java.nio.CharBuffer -import java.nio.charset.{CodingErrorAction, UnmappableCharacterException} +import java.nio.charset.CodingErrorAction +import java.nio.charset.UnmappableCharacterException import java.time.Instant import scala.util.Random diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala index 7ff5d82e..e31853ab 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala @@ -16,12 +16,16 @@ package org.msgpack.core import org.msgpack.core.MessagePack.PackerConfig -import org.msgpack.core.buffer.{ChannelBufferOutput, OutputStreamBufferOutput} +import org.msgpack.core.buffer.ChannelBufferOutput +import org.msgpack.core.buffer.OutputStreamBufferOutput import org.msgpack.value.ValueFactory import wvlet.airspec.AirSpec import wvlet.log.io.IOUtil.withResource -import java.io.{ByteArrayOutputStream, File, FileInputStream, FileOutputStream} +import java.io.ByteArrayOutputStream +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream import scala.util.Random /** diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala index adab4708..bf43591a 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala @@ -15,7 +15,8 @@ // package org.msgpack.core -import org.msgpack.core.MessagePackSpec.{createMessagePackData, toHex} +import org.msgpack.core.MessagePackSpec.createMessagePackData +import org.msgpack.core.MessagePackSpec.toHex import org.msgpack.core.buffer.* import org.msgpack.value.ValueType import wvlet.airspec.AirSpec @@ -67,8 +68,8 @@ class MessageUnpackerTest extends AirSpec with Benchmark: private val intSeq = ( - for (i <- 0 until 100) - yield Random.nextInt() + for i <- 0 until 100 + yield Random.nextInt() ).toArray[Int] private def testData2: Array[Byte] = diff --git a/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferInputTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferInputTest.scala index 5e6c1f96..0465aa69 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferInputTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferInputTest.scala @@ -22,9 +22,13 @@ import wvlet.log.io.IOUtil.withResource import java.io.* import java.net.InetSocketAddress import java.nio.ByteBuffer -import java.nio.channels.{ServerSocketChannel, SocketChannel} -import java.util.concurrent.{Callable, Executors, TimeUnit} -import java.util.zip.{GZIPInputStream, GZIPOutputStream} +import java.nio.channels.ServerSocketChannel +import java.nio.channels.SocketChannel +import java.util.concurrent.Callable +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit +import java.util.zip.GZIPInputStream +import java.util.zip.GZIPOutputStream import scala.util.Random class MessageBufferInputTest extends AirSpec: diff --git a/msgpack-core/src/test/scala/org/msgpack/value/ValueTypeTest.scala b/msgpack-core/src/test/scala/org/msgpack/value/ValueTypeTest.scala index 7b992f28..53707c99 100644 --- a/msgpack-core/src/test/scala/org/msgpack/value/ValueTypeTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/value/ValueTypeTest.scala @@ -16,7 +16,8 @@ package org.msgpack.value import org.msgpack.core.MessagePack.Code.* -import org.msgpack.core.{MessageFormat, MessageFormatException} +import org.msgpack.core.MessageFormat +import org.msgpack.core.MessageFormatException import wvlet.airspec.AirSpec /** diff --git a/msgpack-core/src/test/scala/org/msgpack/value/VariableTest.scala b/msgpack-core/src/test/scala/org/msgpack/value/VariableTest.scala index 2f3cbf9c..d4754e83 100644 --- a/msgpack-core/src/test/scala/org/msgpack/value/VariableTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/value/VariableTest.scala @@ -15,7 +15,9 @@ // package org.msgpack.value -import org.msgpack.core.{MessagePack, MessagePacker, MessageTypeCastException} +import org.msgpack.core.MessagePack +import org.msgpack.core.MessagePacker +import org.msgpack.core.MessageTypeCastException import wvlet.airspec.AirSpec import wvlet.airspec.spi.PropertyCheck