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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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