Merge commit '48f6b61' (version v0.8) into import
Change-Id: Icb233d0c82a2fb3c2ee0cb8e0a3cf93360f22613
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c6b54c9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+*.class
+*.jar
+/target
+.classpath
+.project
+.settings
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..6fb1cdb
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,18 @@
+language: java
+
+sudo: false
+
+env:
+ global:
+ secure: "bEwUUf3355VeqQZYTO0wsZKogquTUNwPQIwKWyHTGGaEVayTwfF2sMEzWojgDPA7E6EbWmSKSm0RKFpkpu5nWr7NvnaoJa/+BpRL/69Y5qB29qVNrCyWM2ZLaoEcTxrqeLKm1ma8TA7IOLAQnxEMZYar/siV9ycDOptp2ZzUoIM="
+
+addons:
+ coverity_scan:
+ project:
+ name: "c-rack/cbor-java"
+ description: "Build submitted via Travis CI"
+ notification_email: constantin@rack.li
+ build_command_prepend: "mvn clean"
+ build_command: "mvn -DskipTests=true compile"
+ branch_pattern: master
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e06d208
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ 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.
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ab05a6a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,98 @@
+cbor-java
+=========
+
+A Java 7 implementation of [RFC 7049](http://tools.ietf.org/html/rfc7049): Concise Binary Object Representation ([CBOR](http://cbor.io/))
+
+
+[![Build Status](https://travis-ci.org/c-rack/cbor-java.svg?branch=master)](https://travis-ci.org/c-rack/cbor-java)
+[![Coverage Status](https://coveralls.io/repos/c-rack/cbor-java/badge.svg?branch=master&service=github)](https://coveralls.io/github/c-rack/cbor-java?branch=master)
+[![Coverity Scan Build Status](https://scan.coverity.com/projects/1218/badge.svg)](https://scan.coverity.com/projects/1218)
+[![Dependency Status](https://www.versioneye.com/user/projects/555e2fb6634daa30fb000ea0/badge.svg?style=flat)](https://www.versioneye.com/user/projects/555e2fb6634daa30fb000ea0)
+
+
+## Features
+
+* Encodes and decodes **all examples** described in RFC 7049
+* Provides a **fluent interface builder** for CBOR messages
+* Supports semantic tags
+* Supports 64-bit integer values
+* Passes all [CPD](http://c-rack.github.io/cbor-java/cpd.html), [PMD](http://c-rack.github.io/cbor-java/pmd.html) and [FindBugs](http://c-rack.github.io/cbor-java/findbugs.html) tests
+
+## Documentation
+
+* [Documentation](http://c-rack.github.io/cbor-java/)
+* [JavaDoc](http://c-rack.github.io/cbor-java/apidocs/index.html)
+
+## Maven Dependency
+
+Add this to the dependencies section of your pom.xml file:
+
+```xml
+<dependency>
+ <groupId>co.nstant.in</groupId>
+ <artifactId>cbor</artifactId>
+ <version>0.8</version>
+</dependency>
+```
+
+## Usage
+
+### Encoding Example
+
+```java
+ByteArrayOutputStream baos = new ByteArrayOutputStream();
+new CborEncoder(baos).encode(new CborBuilder()
+ .add("text") // add string
+ .add(1234) // add integer
+ .add(new byte[] { 0x10 }) // add byte array
+ .addArray() // add array
+ .add(1)
+ .add("text")
+ .end()
+ .build());
+byte[] encodedBytes = baos.toByteArray();
+```
+
+### Decoding Example
+
+```java
+ByteArrayInputStream bais = new ByteArrayInputStream(encodedBytes);
+List<DataItem> dataItems = new CborDecoder(bais).decode();
+for(DataItem dataItem : dataItems) {
+ // process data item
+}
+```
+
+### Streaming Decoding Example
+
+```java
+ByteArrayInputStream bais = new ByteArrayInputStream(encodedBytes);
+new CborDecoder(bais).decode(new DataItemListener() {
+
+ @Override
+ public void onDataItem(DataItem dataItem) {
+ // process data item
+ }
+
+});
+```
+
+## Contribution Process
+
+This project uses the [C4 process](https://rfc.zeromq.org/spec:42/C4/) for all code changes.
+
+## License
+
+ Copyright 2013-2017 Constantin Rack
+
+ 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.
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..40aee1c
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,260 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>co.nstant.in</groupId>
+ <artifactId>cbor</artifactId>
+ <version>0.8</version>
+ <name>CBOR for Java</name>
+ <description>Java implementation of RFC 7049: Concise Binary Object Representation (CBOR)</description>
+ <url>https://github.com/c-rack/cbor-java</url>
+ <licenses>
+ <license>
+ <name>The Apache Software License, Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ <distribution>repo</distribution>
+ <comments>A business-friendly OSS license</comments>
+ </license>
+ </licenses>
+ <prerequisites>
+ <maven>3.0.1</maven>
+ </prerequisites>
+ <scm>
+ <url>https://github.com/c-rack/cbor-java</url>
+ </scm>
+ <distributionManagement>
+ <snapshotRepository>
+ <id>ossrh</id>
+ <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+ </snapshotRepository>
+ <repository>
+ <id>ossrh</id>
+ <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+ </repository>
+ </distributionManagement>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ <github.global.server>github</github.global.server>
+ </properties>
+ <developers>
+ <developer>
+ <id>crack</id>
+ <name>Constantin Rack</name>
+ <email>constantin@rack.li</email>
+ <url>http://co.nstant.in/</url>
+ <roles>
+ <role>developer</role>
+ </roles>
+ <timezone>Europe/Berlin</timezone>
+ </developer>
+ <developer>
+ <id>marandus</id>
+ <name>Thomas Rix</name>
+ <email>rix@decoit.de</email>
+ <url>http://www.decoit.de/</url>
+ <roles>
+ <role>developer</role>
+ </roles>
+ <timezone>Europe/Berlin</timezone>
+ </developer>
+ </developers>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <version>1.5</version>
+ <executions>
+ <execution>
+ <id>sign-artifacts</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>sign</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.eluder.coveralls</groupId>
+ <artifactId>coveralls-maven-plugin</artifactId>
+ <version>4.3.0</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.7.0</version>
+ <configuration>
+ <source>1.7</source>
+ <target>1.7</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <version>3.0.1</version>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.10.4</version>
+ <executions>
+ <execution>
+ <id>attach-javadocs</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-site-plugin</artifactId>
+ <version>3.6</version>
+ <configuration>
+ <locales>en</locales>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>lt.velykis.maven.skins</groupId>
+ <artifactId>reflow-velocity-tools</artifactId>
+ <version>1.1.1</version>
+ </dependency>
+ <!-- Reflow skin requires Velocity >= 1.7 -->
+ <dependency>
+ <groupId>org.apache.velocity</groupId>
+ <artifactId>velocity</artifactId>
+ <version>1.7</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ <plugin>
+ <groupId>com.github.github</groupId>
+ <artifactId>site-maven-plugin</artifactId>
+ <version>0.12</version>
+ <configuration>
+ <message>Creating site for ${project.version}</message>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>site</goal>
+ </goals>
+ <phase>site</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.jacoco</groupId>
+ <artifactId>jacoco-maven-plugin</artifactId>
+ <version>0.7.9</version>
+ <executions>
+ <execution>
+ <id>prepare-agent</id>
+ <goals>
+ <goal>prepare-agent</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-pmd-plugin</artifactId>
+ <version>3.8</version>
+ <configuration>
+ <skipEmptyReport>false</skipEmptyReport>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.sonatype.plugins</groupId>
+ <artifactId>nexus-staging-maven-plugin</artifactId>
+ <version>1.6.7</version>
+ <extensions>true</extensions>
+ <configuration>
+ <serverId>ossrh</serverId>
+ <nexusUrl>https://oss.sonatype.org/</nexusUrl>
+ <autoReleaseAfterClose>true</autoReleaseAfterClose>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jxr-plugin</artifactId>
+ <version>2.5</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-report-plugin</artifactId>
+ <version>2.20.1</version>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>findbugs-maven-plugin</artifactId>
+ <version>3.0.5</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-pmd-plugin</artifactId>
+ <version>3.8</version>
+ <configuration>
+ <skipEmptyReport>false</skipEmptyReport>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>jdepend-maven-plugin</artifactId>
+ <version>2.0</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-project-info-reports-plugin</artifactId>
+ <version>2.9</version>
+ <reportSets>
+ <reportSet>
+ <reports><!-- select reports -->
+ <report>index</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.10.4</version>
+ <reportSets>
+ <reportSet><!-- by default, id = "default" -->
+ <reports><!-- select non-aggregate reports -->
+ <report>javadoc</report>
+ <report>test-javadoc</report>
+ </reports>
+ </reportSet>
+ <reportSet><!-- aggregate reportSet, to define in poms having modules -->
+ <id>aggregate</id>
+ <inherited>false</inherited><!-- don't run aggregate in child modules -->
+ <reports>
+ <report>aggregate</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ </plugins>
+ </reporting>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/src/main/java/co/nstant/in/cbor/CborBuilder.java b/src/main/java/co/nstant/in/cbor/CborBuilder.java
new file mode 100644
index 0000000..8dc1ef9
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/CborBuilder.java
@@ -0,0 +1,129 @@
+package co.nstant.in.cbor;
+
+import java.math.BigInteger;
+import java.util.LinkedList;
+import java.util.List;
+
+import co.nstant.in.cbor.builder.AbstractBuilder;
+import co.nstant.in.cbor.builder.ArrayBuilder;
+import co.nstant.in.cbor.builder.ByteStringBuilder;
+import co.nstant.in.cbor.builder.MapBuilder;
+import co.nstant.in.cbor.builder.UnicodeStringBuilder;
+import co.nstant.in.cbor.model.Array;
+import co.nstant.in.cbor.model.ByteString;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Map;
+import co.nstant.in.cbor.model.UnicodeString;
+
+public class CborBuilder extends AbstractBuilder<CborBuilder> {
+
+ private final List<DataItem> dataItems = new LinkedList<>();
+
+ public CborBuilder() {
+ super(null);
+ }
+
+ public CborBuilder reset() {
+ dataItems.clear();
+ return this;
+ }
+
+ public List<DataItem> build() {
+ return dataItems;
+ }
+
+ public CborBuilder add(DataItem dataItem) {
+ dataItems.add(dataItem);
+ return this;
+ }
+
+ public CborBuilder add(long value) {
+ add(convert(value));
+ return this;
+ }
+
+ public CborBuilder add(BigInteger value) {
+ add(convert(value));
+ return this;
+ }
+
+ public CborBuilder add(boolean value) {
+ add(convert(value));
+ return this;
+ }
+
+ public CborBuilder add(float value) {
+ add(convert(value));
+ return this;
+ }
+
+ public CborBuilder add(double value) {
+ add(convert(value));
+ return this;
+ }
+
+ public CborBuilder add(byte[] bytes) {
+ add(convert(bytes));
+ return this;
+ }
+
+ public ByteStringBuilder<CborBuilder> startByteString() {
+ return startByteString(null);
+ }
+
+ public ByteStringBuilder<CborBuilder> startByteString(byte[] bytes) {
+ add(new ByteString(bytes).setChunked(true));
+ return new ByteStringBuilder<CborBuilder>(this);
+ }
+
+ public CborBuilder add(String string) {
+ add(convert(string));
+ return this;
+ }
+
+ public UnicodeStringBuilder<CborBuilder> startString() {
+ return startString(null);
+ }
+
+ public UnicodeStringBuilder<CborBuilder> startString(String string) {
+ add(new UnicodeString(string).setChunked(true));
+ return new UnicodeStringBuilder<CborBuilder>(this);
+ }
+
+ public CborBuilder addTag(long value) {
+ add(tag(value));
+ return this;
+ }
+
+ public ArrayBuilder<CborBuilder> startArray() {
+ Array array = new Array();
+ array.setChunked(true);
+ add(array);
+ return new ArrayBuilder<CborBuilder>(this, array);
+ }
+
+ public ArrayBuilder<CborBuilder> addArray() {
+ Array array = new Array();
+ add(array);
+ return new ArrayBuilder<CborBuilder>(this, array);
+ }
+
+ public MapBuilder<CborBuilder> addMap() {
+ Map map = new Map();
+ add(map);
+ return new MapBuilder<CborBuilder>(this, map);
+ }
+
+ public MapBuilder<CborBuilder> startMap() {
+ Map map = new Map();
+ map.setChunked(true);
+ add(map);
+ return new MapBuilder<CborBuilder>(this, map);
+ }
+
+ @Override
+ protected void addChunk(DataItem dataItem) {
+ add(dataItem);
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/CborDecoder.java b/src/main/java/co/nstant/in/cbor/CborDecoder.java
new file mode 100644
index 0000000..d726101
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/CborDecoder.java
@@ -0,0 +1,288 @@
+package co.nstant.in.cbor;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+
+import co.nstant.in.cbor.decoder.ArrayDecoder;
+import co.nstant.in.cbor.decoder.ByteStringDecoder;
+import co.nstant.in.cbor.decoder.MapDecoder;
+import co.nstant.in.cbor.decoder.NegativeIntegerDecoder;
+import co.nstant.in.cbor.decoder.SpecialDecoder;
+import co.nstant.in.cbor.decoder.TagDecoder;
+import co.nstant.in.cbor.decoder.UnicodeStringDecoder;
+import co.nstant.in.cbor.decoder.UnsignedIntegerDecoder;
+import co.nstant.in.cbor.model.Array;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.LanguageTaggedString;
+import co.nstant.in.cbor.model.MajorType;
+import co.nstant.in.cbor.model.Number;
+import co.nstant.in.cbor.model.RationalNumber;
+import co.nstant.in.cbor.model.Tag;
+import co.nstant.in.cbor.model.UnicodeString;
+
+/**
+ * Decoder for the CBOR format based.
+ */
+public class CborDecoder {
+
+ private final InputStream inputStream;
+ private final UnsignedIntegerDecoder unsignedIntegerDecoder;
+ private final NegativeIntegerDecoder negativeIntegerDecoder;
+ private final ByteStringDecoder byteStringDecoder;
+ private final UnicodeStringDecoder unicodeStringDecoder;
+ private final ArrayDecoder arrayDecoder;
+ private final MapDecoder mapDecoder;
+ private final TagDecoder tagDecoder;
+ private final SpecialDecoder specialDecoder;
+
+ private boolean autoDecodeInfinitiveArrays = true;
+ private boolean autoDecodeInfinitiveMaps = true;
+ private boolean autoDecodeInfinitiveByteStrings = true;
+ private boolean autoDecodeInfinitiveUnicodeStrings = true;
+ private boolean autoDecodeRationalNumbers = true;
+ private boolean autoDecodeLanguageTaggedStrings = true;
+ private boolean rejectDuplicateKeys = false;
+
+ /**
+ * Initialize a new decoder which reads the binary encoded data from an
+ * {@link InputStream}.
+ */
+ public CborDecoder(InputStream inputStream) {
+ Objects.requireNonNull(inputStream);
+ this.inputStream = inputStream;
+ unsignedIntegerDecoder = new UnsignedIntegerDecoder(this, inputStream);
+ negativeIntegerDecoder = new NegativeIntegerDecoder(this, inputStream);
+ byteStringDecoder = new ByteStringDecoder(this, inputStream);
+ unicodeStringDecoder = new UnicodeStringDecoder(this, inputStream);
+ arrayDecoder = new ArrayDecoder(this, inputStream);
+ mapDecoder = new MapDecoder(this, inputStream);
+ tagDecoder = new TagDecoder(this, inputStream);
+ specialDecoder = new SpecialDecoder(this, inputStream);
+ }
+
+ /**
+ * Convenience method to decode a byte array directly.
+ *
+ * @param bytes
+ * the CBOR encoded data
+ * @return a list of {@link DataItem}s
+ * @throws CborException
+ * if decoding failed
+ */
+ public static List<DataItem> decode(byte[] bytes) throws CborException {
+ return new CborDecoder(new ByteArrayInputStream(bytes)).decode();
+ }
+
+ /**
+ * Decode the {@link InputStream} to a list of {@link DataItem}s.
+ *
+ * @return the list of {@link DataItem}s
+ * @throws CborException
+ * if decoding failed
+ */
+ public List<DataItem> decode() throws CborException {
+ List<DataItem> dataItems = new LinkedList<>();
+ DataItem dataItem;
+ while ((dataItem = decodeNext()) != null) {
+ dataItems.add(dataItem);
+ }
+ return dataItems;
+ }
+
+ /**
+ * Streaming decoding of an input stream. On each decoded DataItem, the
+ * callback listener is invoked.
+ *
+ * @param dataItemListener
+ * the callback listener
+ * @throws CborException
+ * if decoding failed
+ */
+ public void decode(DataItemListener dataItemListener) throws CborException {
+ Objects.requireNonNull(dataItemListener);
+ DataItem dataItem = decodeNext();
+ while (dataItem != null) {
+ dataItemListener.onDataItem(dataItem);
+ dataItem = decodeNext();
+ }
+ }
+
+ /**
+ * Decodes exactly one DataItem from the input stream.
+ *
+ * @return a {@link DataItem} or null if end of stream has reached.
+ * @throws CborException
+ * if decoding failed
+ */
+ public DataItem decodeNext() throws CborException {
+ int symbol;
+ try {
+ symbol = inputStream.read();
+ } catch (IOException ioException) {
+ throw new CborException(ioException);
+ }
+ if (symbol == -1) {
+ return null;
+ }
+ switch (MajorType.ofByte(symbol)) {
+ case ARRAY:
+ return arrayDecoder.decode(symbol);
+ case BYTE_STRING:
+ return byteStringDecoder.decode(symbol);
+ case MAP:
+ return mapDecoder.decode(symbol);
+ case NEGATIVE_INTEGER:
+ return negativeIntegerDecoder.decode(symbol);
+ case UNICODE_STRING:
+ return unicodeStringDecoder.decode(symbol);
+ case UNSIGNED_INTEGER:
+ return unsignedIntegerDecoder.decode(symbol);
+ case SPECIAL:
+ return specialDecoder.decode(symbol);
+ case TAG:
+ Tag tag = tagDecoder.decode(symbol);
+ DataItem next = decodeNext();
+ if (next == null) {
+ throw new CborException("Unexpected end of stream: tag without following data item.");
+ } else {
+ if (autoDecodeRationalNumbers && tag.getValue() == 30) {
+ return decodeRationalNumber(next);
+ } else if (autoDecodeLanguageTaggedStrings && tag.getValue() == 38) {
+ return decodeLanguageTaggedString(next);
+ } else {
+ DataItem itemToTag = next;
+ while (itemToTag.hasTag())
+ itemToTag = itemToTag.getTag();
+ itemToTag.setTag(tag);
+ return next;
+ }
+ }
+ case INVALID:
+ default:
+ throw new CborException("Not implemented major type " + symbol);
+ }
+ }
+
+ private DataItem decodeLanguageTaggedString(DataItem dataItem) throws CborException {
+ if (!(dataItem instanceof Array)) {
+ throw new CborException("Error decoding LanguageTaggedString: not an array");
+ }
+
+ Array array = (Array) dataItem;
+
+ if (array.getDataItems().size() != 2) {
+ throw new CborException("Error decoding LanguageTaggedString: array size is not 2");
+ }
+
+ DataItem languageDataItem = array.getDataItems().get(0);
+
+ if (!(languageDataItem instanceof UnicodeString)) {
+ throw new CborException("Error decoding LanguageTaggedString: first data item is not an UnicodeString");
+ }
+
+ DataItem stringDataItem = array.getDataItems().get(1);
+
+ if (!(stringDataItem instanceof UnicodeString)) {
+ throw new CborException("Error decoding LanguageTaggedString: second data item is not an UnicodeString");
+ }
+
+ UnicodeString language = (UnicodeString) languageDataItem;
+ UnicodeString string = (UnicodeString) stringDataItem;
+
+ return new LanguageTaggedString(language, string);
+ }
+
+ private DataItem decodeRationalNumber(DataItem dataItem) throws CborException {
+ if (!(dataItem instanceof Array)) {
+ throw new CborException("Error decoding RationalNumber: not an array");
+ }
+
+ Array array = (Array) dataItem;
+
+ if (array.getDataItems().size() != 2) {
+ throw new CborException("Error decoding RationalNumber: array size is not 2");
+ }
+
+ DataItem numeratorDataItem = array.getDataItems().get(0);
+
+ if (!(numeratorDataItem instanceof Number)) {
+ throw new CborException("Error decoding RationalNumber: first data item is not a number");
+ }
+
+ DataItem denominatorDataItem = array.getDataItems().get(1);
+
+ if (!(denominatorDataItem instanceof Number)) {
+ throw new CborException("Error decoding RationalNumber: second data item is not a number");
+ }
+
+ Number numerator = (Number) numeratorDataItem;
+ Number denominator = (Number) denominatorDataItem;
+
+ return new RationalNumber(numerator, denominator);
+ }
+
+ public boolean isAutoDecodeInfinitiveArrays() {
+ return autoDecodeInfinitiveArrays;
+ }
+
+ public void setAutoDecodeInfinitiveArrays(boolean autoDecodeInfinitiveArrays) {
+ this.autoDecodeInfinitiveArrays = autoDecodeInfinitiveArrays;
+ }
+
+ public boolean isAutoDecodeInfinitiveMaps() {
+ return autoDecodeInfinitiveMaps;
+ }
+
+ public void setAutoDecodeInfinitiveMaps(boolean autoDecodeInfinitiveMaps) {
+ this.autoDecodeInfinitiveMaps = autoDecodeInfinitiveMaps;
+ }
+
+ public boolean isAutoDecodeInfinitiveByteStrings() {
+ return autoDecodeInfinitiveByteStrings;
+ }
+
+ public void setAutoDecodeInfinitiveByteStrings(
+ boolean autoDecodeInfinitiveByteStrings) {
+ this.autoDecodeInfinitiveByteStrings = autoDecodeInfinitiveByteStrings;
+ }
+
+ public boolean isAutoDecodeInfinitiveUnicodeStrings() {
+ return autoDecodeInfinitiveUnicodeStrings;
+ }
+
+ public void setAutoDecodeInfinitiveUnicodeStrings(
+ boolean autoDecodeInfinitiveUnicodeStrings) {
+ this.autoDecodeInfinitiveUnicodeStrings = autoDecodeInfinitiveUnicodeStrings;
+ }
+
+ public boolean isAutoDecodeRationalNumbers() {
+ return autoDecodeRationalNumbers;
+ }
+
+ public void setAutoDecodeRationalNumbers(
+ boolean autoDecodeRationalNumbers) {
+ this.autoDecodeRationalNumbers = autoDecodeRationalNumbers;
+ }
+
+ public boolean isAutoDecodeLanguageTaggedStrings() {
+ return autoDecodeLanguageTaggedStrings;
+ }
+
+ public void setAutoDecodeLanguageTaggedStrings(
+ boolean autoDecodeLanguageTaggedStrings) {
+ this.autoDecodeLanguageTaggedStrings = autoDecodeLanguageTaggedStrings;
+ }
+
+ public boolean isRejectDuplicateKeys() {
+ return rejectDuplicateKeys;
+ }
+
+ public void setRejectDuplicateKeys(boolean rejectDuplicateKeys) {
+ this.rejectDuplicateKeys = rejectDuplicateKeys;
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/CborEncoder.java b/src/main/java/co/nstant/in/cbor/CborEncoder.java
new file mode 100644
index 0000000..06d5387
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/CborEncoder.java
@@ -0,0 +1,121 @@
+package co.nstant.in.cbor;
+
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Objects;
+
+import co.nstant.in.cbor.encoder.ArrayEncoder;
+import co.nstant.in.cbor.encoder.ByteStringEncoder;
+import co.nstant.in.cbor.encoder.MapEncoder;
+import co.nstant.in.cbor.encoder.NegativeIntegerEncoder;
+import co.nstant.in.cbor.encoder.SpecialEncoder;
+import co.nstant.in.cbor.encoder.TagEncoder;
+import co.nstant.in.cbor.encoder.UnicodeStringEncoder;
+import co.nstant.in.cbor.encoder.UnsignedIntegerEncoder;
+import co.nstant.in.cbor.model.Array;
+import co.nstant.in.cbor.model.ByteString;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Map;
+import co.nstant.in.cbor.model.NegativeInteger;
+import co.nstant.in.cbor.model.SimpleValue;
+import co.nstant.in.cbor.model.Special;
+import co.nstant.in.cbor.model.Tag;
+import co.nstant.in.cbor.model.UnicodeString;
+import co.nstant.in.cbor.model.UnsignedInteger;
+
+/**
+ * Encoder for the CBOR format based.
+ */
+public class CborEncoder {
+
+ private final UnsignedIntegerEncoder unsignedIntegerEncoder;
+ private final NegativeIntegerEncoder negativeIntegerEncoder;
+ private final ByteStringEncoder byteStringEncoder;
+ private final UnicodeStringEncoder unicodeStringEncoder;
+ private final ArrayEncoder arrayEncoder;
+ private final MapEncoder mapEncoder;
+ private final TagEncoder tagEncoder;
+ private final SpecialEncoder specialEncoder;
+
+ /**
+ * Initialize a new encoder which writes the binary encoded data to an
+ * {@link OutputStream}.
+ */
+ public CborEncoder(OutputStream outputStream) {
+ Objects.requireNonNull(outputStream);
+ unsignedIntegerEncoder = new UnsignedIntegerEncoder(this, outputStream);
+ negativeIntegerEncoder = new NegativeIntegerEncoder(this, outputStream);
+ byteStringEncoder = new ByteStringEncoder(this, outputStream);
+ unicodeStringEncoder = new UnicodeStringEncoder(this, outputStream);
+ arrayEncoder = new ArrayEncoder(this, outputStream);
+ mapEncoder = new MapEncoder(this, outputStream);
+ tagEncoder = new TagEncoder(this, outputStream);
+ specialEncoder = new SpecialEncoder(this, outputStream);
+ }
+
+ /**
+ * Encode a list of {@link DataItem}s, also known as a stream.
+ *
+ * @param dataItems
+ * a list of {@link DataItem}s
+ * @throws CborException
+ * if the {@link DataItem}s could not be encoded or there was an
+ * problem with the {@link OutputStream}.
+ */
+ public void encode(List<DataItem> dataItems) throws CborException {
+ for (DataItem dataItem : dataItems) {
+ encode(dataItem);
+ }
+ }
+
+ /**
+ * Encode a single {@link DataItem}.
+ *
+ * @param dataItem
+ * the {@link DataItem} to encode. If null, encoder encodes a
+ * {@link SimpleValue} NULL value.
+ * @throws CborException
+ * if {@link DataItem} could not be encoded or there was an
+ * problem with the {@link OutputStream}.
+ */
+ public void encode(DataItem dataItem) throws CborException {
+ if (dataItem == null) {
+ dataItem = SimpleValue.NULL;
+ }
+
+ if (dataItem.hasTag()) {
+ Tag tagDi = dataItem.getTag();
+ tagEncoder.encode(tagDi);
+ }
+
+ switch (dataItem.getMajorType()) {
+ case UNSIGNED_INTEGER:
+ unsignedIntegerEncoder.encode((UnsignedInteger) dataItem);
+ break;
+ case NEGATIVE_INTEGER:
+ negativeIntegerEncoder.encode((NegativeInteger) dataItem);
+ break;
+ case BYTE_STRING:
+ byteStringEncoder.encode((ByteString) dataItem);
+ break;
+ case UNICODE_STRING:
+ unicodeStringEncoder.encode((UnicodeString) dataItem);
+ break;
+ case ARRAY:
+ arrayEncoder.encode((Array) dataItem);
+ break;
+ case MAP:
+ mapEncoder.encode((Map) dataItem);
+ break;
+ case SPECIAL:
+ specialEncoder.encode((Special) dataItem);
+ break;
+ case TAG:
+ tagEncoder.encode((Tag) dataItem);
+ break;
+ default:
+ throw new CborException("Unknown major type");
+ }
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/CborException.java b/src/main/java/co/nstant/in/cbor/CborException.java
new file mode 100644
index 0000000..d4708c9
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/CborException.java
@@ -0,0 +1,19 @@
+package co.nstant.in.cbor;
+
+public class CborException extends Exception {
+
+ private static final long serialVersionUID = 8839905301881841410L;
+
+ public CborException(String message) {
+ super(message);
+ }
+
+ public CborException(Throwable cause) {
+ super(cause);
+ }
+
+ public CborException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/DataItemListener.java b/src/main/java/co/nstant/in/cbor/DataItemListener.java
new file mode 100644
index 0000000..2044954
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/DataItemListener.java
@@ -0,0 +1,15 @@
+package co.nstant.in.cbor;
+
+import co.nstant.in.cbor.model.DataItem;
+
+/**
+ * Callback interface for a streaming {@link CborDecoder}.
+ */
+public interface DataItemListener {
+
+ /**
+ * Gets called on every decoded {@link DataItem}.
+ */
+ void onDataItem(DataItem dataItem);
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/builder/AbstractBuilder.java b/src/main/java/co/nstant/in/cbor/builder/AbstractBuilder.java
new file mode 100644
index 0000000..2b227b5
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/builder/AbstractBuilder.java
@@ -0,0 +1,113 @@
+package co.nstant.in.cbor.builder;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.decoder.HalfPrecisionFloatDecoder;
+import co.nstant.in.cbor.encoder.HalfPrecisionFloatEncoder;
+import co.nstant.in.cbor.model.ByteString;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.DoublePrecisionFloat;
+import co.nstant.in.cbor.model.HalfPrecisionFloat;
+import co.nstant.in.cbor.model.NegativeInteger;
+import co.nstant.in.cbor.model.SimpleValue;
+import co.nstant.in.cbor.model.SinglePrecisionFloat;
+import co.nstant.in.cbor.model.Tag;
+import co.nstant.in.cbor.model.UnicodeString;
+import co.nstant.in.cbor.model.UnsignedInteger;
+
+public abstract class AbstractBuilder<T> {
+
+ private final T parent;
+
+ public AbstractBuilder(T parent) {
+ this.parent = parent;
+ }
+
+ protected T getParent() {
+ return parent;
+ }
+
+ protected void addChunk(DataItem dataItem) {
+ throw new IllegalStateException();
+ }
+
+ protected DataItem convert(long value) {
+ if (value >= 0) {
+ return new UnsignedInteger(value);
+ } else {
+ return new NegativeInteger(value);
+ }
+ }
+
+ protected DataItem convert(BigInteger value) {
+ if (value.signum() == -1) {
+ return new NegativeInteger(value);
+ } else {
+ return new UnsignedInteger(value);
+ }
+ }
+
+ protected DataItem convert(boolean value) {
+ if (value) {
+ return SimpleValue.TRUE;
+ } else {
+ return SimpleValue.FALSE;
+ }
+ }
+
+ protected DataItem convert(byte[] bytes) {
+ return new ByteString(bytes);
+ }
+
+ protected DataItem convert(String string) {
+ return new UnicodeString(string);
+ }
+
+ protected DataItem convert(float value) {
+ if (isHalfPrecisionEnough(value)) {
+ return new HalfPrecisionFloat(value);
+ } else {
+ return new SinglePrecisionFloat(value);
+ }
+ }
+
+ protected DataItem convert(double value) {
+ return new DoublePrecisionFloat(value);
+ }
+
+ protected Tag tag(long value) {
+ return new Tag(value);
+ }
+
+ private boolean isHalfPrecisionEnough(float value) {
+ try {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ HalfPrecisionFloatEncoder encoder = getHalfPrecisionFloatEncoder(outputStream);
+ encoder.encode(new HalfPrecisionFloat(value));
+ byte[] bytes = outputStream.toByteArray();
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
+ HalfPrecisionFloatDecoder decoder = getHalfPrecisionFloatDecoder(inputStream);
+ if (inputStream.read() == -1) { // to skip type byte
+ throw new CborException("unexpected end of stream");
+ }
+ HalfPrecisionFloat halfPrecisionFloat = decoder.decode(0);
+ return value == halfPrecisionFloat.getValue();
+ } catch (CborException cborException) {
+ return false;
+ }
+ }
+
+ protected HalfPrecisionFloatEncoder getHalfPrecisionFloatEncoder(OutputStream outputStream) {
+ return new HalfPrecisionFloatEncoder(null, outputStream);
+ }
+
+ protected HalfPrecisionFloatDecoder getHalfPrecisionFloatDecoder(InputStream inputStream) {
+ return new HalfPrecisionFloatDecoder(null, inputStream);
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/builder/ArrayBuilder.java b/src/main/java/co/nstant/in/cbor/builder/ArrayBuilder.java
new file mode 100644
index 0000000..274f929
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/builder/ArrayBuilder.java
@@ -0,0 +1,86 @@
+package co.nstant.in.cbor.builder;
+
+import co.nstant.in.cbor.model.Array;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Map;
+import co.nstant.in.cbor.model.SimpleValue;
+
+public class ArrayBuilder<T extends AbstractBuilder<?>> extends
+ AbstractBuilder<T> {
+
+ private final Array array;
+
+ public ArrayBuilder(T parent, Array array) {
+ super(parent);
+ this.array = array;
+ }
+
+ public ArrayBuilder<T> add(DataItem dataItem) {
+ array.add(dataItem);
+ return this;
+ }
+
+ public ArrayBuilder<T> add(long value) {
+ add(convert(value));
+ return this;
+ }
+
+ public ArrayBuilder<T> add(boolean value) {
+ add(convert(value));
+ return this;
+ }
+
+ public ArrayBuilder<T> add(float value) {
+ add(convert(value));
+ return this;
+ }
+
+ public ArrayBuilder<T> add(double value) {
+ add(convert(value));
+ return this;
+ }
+
+ public ArrayBuilder<T> add(byte[] bytes) {
+ add(convert(bytes));
+ return this;
+ }
+
+ public ArrayBuilder<T> add(String string) {
+ add(convert(string));
+ return this;
+ }
+
+ public ArrayBuilder<ArrayBuilder<T>> addArray() {
+ Array nestedArray = new Array();
+ add(nestedArray);
+ return new ArrayBuilder<ArrayBuilder<T>>(this, nestedArray);
+ }
+
+ public ArrayBuilder<ArrayBuilder<T>> startArray() {
+ Array nestedArray = new Array();
+ nestedArray.setChunked(true);
+ add(nestedArray);
+ return new ArrayBuilder<ArrayBuilder<T>>(this, nestedArray);
+ }
+
+ public MapBuilder<ArrayBuilder<T>> addMap() {
+ Map nestedMap = new Map();
+ add(nestedMap);
+ return new MapBuilder<ArrayBuilder<T>>(this, nestedMap);
+ }
+
+ public MapBuilder<ArrayBuilder<T>> startMap() {
+ Map nestedMap = new Map();
+ nestedMap.setChunked(true);
+ add(nestedMap);
+ return new MapBuilder<ArrayBuilder<T>>(this, nestedMap);
+ }
+
+ public T end() {
+ if (array.isChunked()) {
+ add(SimpleValue.BREAK);
+ }
+ return getParent();
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/builder/ByteStringBuilder.java b/src/main/java/co/nstant/in/cbor/builder/ByteStringBuilder.java
new file mode 100644
index 0000000..2f302b5
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/builder/ByteStringBuilder.java
@@ -0,0 +1,22 @@
+package co.nstant.in.cbor.builder;
+
+import co.nstant.in.cbor.model.SimpleValue;
+
+public class ByteStringBuilder<T extends AbstractBuilder<?>> extends
+ AbstractBuilder<T> {
+
+ public ByteStringBuilder(T parent) {
+ super(parent);
+ }
+
+ public ByteStringBuilder<T> add(byte[] bytes) {
+ getParent().addChunk(convert(bytes));
+ return this;
+ }
+
+ public T end() {
+ getParent().addChunk(SimpleValue.BREAK);
+ return getParent();
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/builder/MapBuilder.java b/src/main/java/co/nstant/in/cbor/builder/MapBuilder.java
new file mode 100644
index 0000000..55e4303
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/builder/MapBuilder.java
@@ -0,0 +1,155 @@
+package co.nstant.in.cbor.builder;
+
+import co.nstant.in.cbor.model.Array;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Map;
+
+public class MapBuilder<T extends AbstractBuilder<?>> extends
+ AbstractBuilder<T> {
+
+ private final Map map;
+
+ public MapBuilder(T parent, Map map) {
+ super(parent);
+ this.map = map;
+ }
+
+ public MapBuilder<T> put(DataItem key, DataItem value) {
+ map.put(key, value);
+ return this;
+ }
+
+ public MapBuilder<T> put(long key, long value) {
+ put(convert(key), convert(value));
+ return this;
+ }
+
+ public MapBuilder<T> put(long key, boolean value) {
+ put(convert(key), convert(value));
+ return this;
+ }
+
+ public MapBuilder<T> put(long key, float value) {
+ put(convert(key), convert(value));
+ return this;
+ }
+
+ public MapBuilder<T> put(long key, double value) {
+ put(convert(key), convert(value));
+ return this;
+ }
+
+ public MapBuilder<T> put(long key, byte[] value) {
+ put(convert(key), convert(value));
+ return this;
+ }
+
+ public MapBuilder<T> put(long key, String value) {
+ put(convert(key), convert(value));
+ return this;
+ }
+
+ public MapBuilder<T> put(String key, long value) {
+ put(convert(key), convert(value));
+ return this;
+ }
+
+ public MapBuilder<T> put(String key, boolean value) {
+ put(convert(key), convert(value));
+ return this;
+ }
+
+ public MapBuilder<T> put(String key, float value) {
+ put(convert(key), convert(value));
+ return this;
+ }
+
+ public MapBuilder<T> put(String key, double value) {
+ put(convert(key), convert(value));
+ return this;
+ }
+
+ public MapBuilder<T> put(String key, byte[] value) {
+ map.put(convert(key), convert(value));
+ return this;
+ }
+
+ public MapBuilder<T> put(String key, String value) {
+ put(convert(key), convert(value));
+ return this;
+ }
+
+ public ArrayBuilder<MapBuilder<T>> putArray(DataItem key) {
+ Array array = new Array();
+ put(key, array);
+ return new ArrayBuilder<>(this, array);
+ }
+
+ public ArrayBuilder<MapBuilder<T>> putArray(long key) {
+ Array array = new Array();
+ put(convert(key), array);
+ return new ArrayBuilder<>(this, array);
+ }
+
+ public ArrayBuilder<MapBuilder<T>> putArray(String key) {
+ Array array = new Array();
+ put(convert(key), array);
+ return new ArrayBuilder<>(this, array);
+ }
+
+ public ArrayBuilder<MapBuilder<T>> startArray(DataItem key) {
+ Array array = new Array();
+ array.setChunked(true);
+ put(key, array);
+ return new ArrayBuilder<>(this, array);
+ }
+
+ public ArrayBuilder<MapBuilder<T>> startArray(long key) {
+ return startArray(convert(key));
+ }
+
+ public ArrayBuilder<MapBuilder<T>> startArray(String key) {
+ Array array = new Array();
+ array.setChunked(true);
+ put(convert(key), array);
+ return new ArrayBuilder<>(this, array);
+ }
+
+ public MapBuilder<MapBuilder<T>> putMap(DataItem key) {
+ Map nestedMap = new Map();
+ put(key, nestedMap);
+ return new MapBuilder<>(this, nestedMap);
+ }
+
+ public MapBuilder<MapBuilder<T>> putMap(long key) {
+ Map nestedMap = new Map();
+ put(convert(key), nestedMap);
+ return new MapBuilder<>(this, nestedMap);
+ }
+
+ public MapBuilder<MapBuilder<T>> putMap(String key) {
+ Map nestedMap = new Map();
+ put(convert(key), nestedMap);
+ return new MapBuilder<>(this, nestedMap);
+ }
+
+ public MapBuilder<MapBuilder<T>> startMap(DataItem key) {
+ Map nestedMap = new Map();
+ nestedMap.setChunked(true);
+ put(key, nestedMap);
+ return new MapBuilder<>(this, nestedMap);
+ }
+
+ public MapBuilder<MapBuilder<T>> startMap(long key) {
+ return startMap(convert(key));
+ }
+
+ public MapBuilder<MapBuilder<T>> startMap(String key) {
+ return startMap(convert(key));
+ }
+
+ public T end() {
+ return getParent();
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/builder/UnicodeStringBuilder.java b/src/main/java/co/nstant/in/cbor/builder/UnicodeStringBuilder.java
new file mode 100644
index 0000000..0dd1e24
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/builder/UnicodeStringBuilder.java
@@ -0,0 +1,22 @@
+package co.nstant.in.cbor.builder;
+
+import co.nstant.in.cbor.model.SimpleValue;
+
+public class UnicodeStringBuilder<T extends AbstractBuilder<?>> extends
+ AbstractBuilder<T> {
+
+ public UnicodeStringBuilder(T parent) {
+ super(parent);
+ }
+
+ public UnicodeStringBuilder<T> add(String string) {
+ getParent().addChunk(convert(string));
+ return this;
+ }
+
+ public T end() {
+ getParent().addChunk(SimpleValue.BREAK);
+ return getParent();
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/decoder/AbstractDecoder.java b/src/main/java/co/nstant/in/cbor/decoder/AbstractDecoder.java
new file mode 100644
index 0000000..30d46c9
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/decoder/AbstractDecoder.java
@@ -0,0 +1,119 @@
+package co.nstant.in.cbor.decoder;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.AdditionalInformation;
+
+public abstract class AbstractDecoder<T> {
+
+ protected static final int INFINITY = -1;
+
+ protected final InputStream inputStream;
+ protected final CborDecoder decoder;
+
+ public AbstractDecoder(CborDecoder decoder, InputStream inputStream) {
+ this.decoder = decoder;
+ this.inputStream = inputStream;
+ }
+
+ public abstract T decode(int initialByte) throws CborException;
+
+ protected int nextSymbol() throws CborException {
+ try {
+ int symbol = inputStream.read();
+ if (symbol == -1) {
+ throw new IOException("Unexpected end of stream");
+ }
+ return symbol;
+ } catch (IOException ioException) {
+ throw new CborException(ioException);
+ }
+ }
+
+ protected long getLength(int initialByte) throws CborException {
+ switch (AdditionalInformation.ofByte(initialByte)) {
+ case DIRECT:
+ return initialByte & 31;
+ case ONE_BYTE:
+ return nextSymbol();
+ case TWO_BYTES:
+ long twoByteValue = 0;
+ twoByteValue |= nextSymbol() << 8;
+ twoByteValue |= nextSymbol() << 0;
+ return twoByteValue;
+ case FOUR_BYTES:
+ long fourByteValue = 0L;
+ fourByteValue |= (long) nextSymbol() << 24;
+ fourByteValue |= (long) nextSymbol() << 16;
+ fourByteValue |= (long) nextSymbol() << 8;
+ fourByteValue |= (long) nextSymbol() << 0;
+ return fourByteValue;
+ case EIGHT_BYTES:
+ long eightByteValue = 0;
+ eightByteValue |= (long) nextSymbol() << 56;
+ eightByteValue |= (long) nextSymbol() << 48;
+ eightByteValue |= (long) nextSymbol() << 40;
+ eightByteValue |= (long) nextSymbol() << 32;
+ eightByteValue |= (long) nextSymbol() << 24;
+ eightByteValue |= (long) nextSymbol() << 16;
+ eightByteValue |= (long) nextSymbol() << 8;
+ eightByteValue |= (long) nextSymbol() << 0;
+ return eightByteValue;
+ case INDEFINITE:
+ return INFINITY;
+ case RESERVED:
+ default:
+ throw new CborException("Reserved additional information");
+ }
+ }
+
+ protected BigInteger getLengthAsBigInteger(int initialByte)
+ throws CborException {
+ switch (AdditionalInformation.ofByte(initialByte)) {
+ case DIRECT:
+ return BigInteger.valueOf(initialByte & 31);
+ case ONE_BYTE:
+ return BigInteger.valueOf(nextSymbol());
+ case TWO_BYTES:
+ long twoByteValue = 0;
+ twoByteValue |= nextSymbol() << 8;
+ twoByteValue |= nextSymbol() << 0;
+ return BigInteger.valueOf(twoByteValue);
+ case FOUR_BYTES:
+ long fourByteValue = 0L;
+ fourByteValue |= (long) nextSymbol() << 24;
+ fourByteValue |= (long) nextSymbol() << 16;
+ fourByteValue |= (long) nextSymbol() << 8;
+ fourByteValue |= (long) nextSymbol() << 0;
+ return BigInteger.valueOf(fourByteValue);
+ case EIGHT_BYTES:
+ BigInteger eightByteValue = BigInteger.ZERO;
+ eightByteValue = eightByteValue.or(BigInteger.valueOf(nextSymbol())
+ .shiftLeft(56));
+ eightByteValue = eightByteValue.or(BigInteger.valueOf(nextSymbol())
+ .shiftLeft(48));
+ eightByteValue = eightByteValue.or(BigInteger.valueOf(nextSymbol())
+ .shiftLeft(40));
+ eightByteValue = eightByteValue.or(BigInteger.valueOf(nextSymbol())
+ .shiftLeft(32));
+ eightByteValue = eightByteValue.or(BigInteger.valueOf(nextSymbol())
+ .shiftLeft(24));
+ eightByteValue = eightByteValue.or(BigInteger.valueOf(nextSymbol())
+ .shiftLeft(16));
+ eightByteValue = eightByteValue.or(BigInteger.valueOf(nextSymbol())
+ .shiftLeft(8));
+ eightByteValue = eightByteValue.or(BigInteger.valueOf(nextSymbol())
+ .shiftLeft(0));
+ return eightByteValue;
+ case INDEFINITE:
+ return BigInteger.valueOf(INFINITY);
+ case RESERVED:
+ default:
+ throw new CborException("Reserved additional information");
+ }
+ }
+}
diff --git a/src/main/java/co/nstant/in/cbor/decoder/ArrayDecoder.java b/src/main/java/co/nstant/in/cbor/decoder/ArrayDecoder.java
new file mode 100644
index 0000000..344be10
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/decoder/ArrayDecoder.java
@@ -0,0 +1,59 @@
+package co.nstant.in.cbor.decoder;
+
+import java.io.InputStream;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.Array;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Special;
+
+public class ArrayDecoder extends AbstractDecoder<Array> {
+
+ public ArrayDecoder(CborDecoder decoder, InputStream inputStream) {
+ super(decoder, inputStream);
+ }
+
+ @Override
+ public Array decode(int initialByte) throws CborException {
+ long length = getLength(initialByte);
+ if (length == INFINITY) {
+ return decodeInfinitiveLength();
+ } else {
+ return decodeFixedLength(length);
+ }
+ }
+
+ private Array decodeInfinitiveLength() throws CborException {
+ Array array = new Array();
+ array.setChunked(true);
+ if (decoder.isAutoDecodeInfinitiveArrays()) {
+ DataItem dataItem;
+ for (;;) {
+ dataItem = decoder.decodeNext();
+ if (dataItem == null) {
+ throw new CborException("Unexpected end of stream");
+ }
+ if (Special.BREAK.equals(dataItem)) {
+ array.add(Special.BREAK);
+ break;
+ }
+ array.add(dataItem);
+ }
+ }
+ return array;
+ }
+
+ private Array decodeFixedLength(long length) throws CborException {
+ Array array = new Array();
+ for (long i = 0; i < length; i++) {
+ DataItem dataItem = decoder.decodeNext();
+ if (dataItem == null) {
+ throw new CborException("Unexpected end of stream");
+ }
+ array.add(dataItem);
+ }
+ return array;
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/decoder/ByteStringDecoder.java b/src/main/java/co/nstant/in/cbor/decoder/ByteStringDecoder.java
new file mode 100644
index 0000000..99d6fe8
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/decoder/ByteStringDecoder.java
@@ -0,0 +1,67 @@
+package co.nstant.in.cbor.decoder;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.ByteString;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.MajorType;
+import co.nstant.in.cbor.model.Special;
+
+public class ByteStringDecoder extends AbstractDecoder<ByteString> {
+
+ public ByteStringDecoder(CborDecoder decoder, InputStream inputStream) {
+ super(decoder, inputStream);
+ }
+
+ @Override
+ public ByteString decode(int initialByte) throws CborException {
+ long length = getLength(initialByte);
+ if (length == INFINITY) {
+ if (decoder.isAutoDecodeInfinitiveByteStrings()) {
+ return decodeInfinitiveLength();
+ } else {
+ ByteString byteString = new ByteString(null);
+ byteString.setChunked(true);
+ return byteString;
+ }
+ } else {
+ return decodeFixedLength(length);
+ }
+ }
+
+ private ByteString decodeInfinitiveLength() throws CborException {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ for (;;) {
+ DataItem dataItem = decoder.decodeNext();
+ if (dataItem == null) {
+ throw new CborException("Unexpected end of stream");
+ }
+ MajorType majorType = dataItem.getMajorType();
+ if (Special.BREAK.equals(dataItem)) {
+ break;
+ } else if (majorType == MajorType.BYTE_STRING) {
+ ByteString byteString = (ByteString) dataItem;
+ byte[] byteArray = byteString.getBytes();
+ if (byteArray != null) {
+ bytes.write(byteArray, 0, byteArray.length);
+ }
+ } else {
+ throw new CborException("Unexpected major type "
+ + majorType);
+ }
+ }
+ return new ByteString(bytes.toByteArray());
+ }
+
+ private ByteString decodeFixedLength(long length) throws CborException {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream((int) length);
+ for (long i = 0; i < length; i++) {
+ bytes.write(nextSymbol());
+ }
+ return new ByteString(bytes.toByteArray());
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/decoder/DoublePrecisionFloatDecoder.java b/src/main/java/co/nstant/in/cbor/decoder/DoublePrecisionFloatDecoder.java
new file mode 100644
index 0000000..fe92f88
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/decoder/DoublePrecisionFloatDecoder.java
@@ -0,0 +1,38 @@
+package co.nstant.in.cbor.decoder;
+
+import java.io.InputStream;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DoublePrecisionFloat;
+
+public class DoublePrecisionFloatDecoder extends
+ AbstractDecoder<DoublePrecisionFloat> {
+
+ public DoublePrecisionFloatDecoder(CborDecoder decoder,
+ InputStream inputStream) {
+ super(decoder, inputStream);
+ }
+
+ @Override
+ public DoublePrecisionFloat decode(int initialByte) throws CborException {
+ long bits = 0;
+ bits |= nextSymbol() & 0xFF;
+ bits <<= 8;
+ bits |= nextSymbol() & 0xFF;
+ bits <<= 8;
+ bits |= nextSymbol() & 0xFF;
+ bits <<= 8;
+ bits |= nextSymbol() & 0xFF;
+ bits <<= 8;
+ bits |= nextSymbol() & 0xFF;
+ bits <<= 8;
+ bits |= nextSymbol() & 0xFF;
+ bits <<= 8;
+ bits |= nextSymbol() & 0xFF;
+ bits <<= 8;
+ bits |= nextSymbol() & 0xFF;
+ return new DoublePrecisionFloat(Double.longBitsToDouble(bits));
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/decoder/HalfPrecisionFloatDecoder.java b/src/main/java/co/nstant/in/cbor/decoder/HalfPrecisionFloatDecoder.java
new file mode 100644
index 0000000..ec3cc2d
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/decoder/HalfPrecisionFloatDecoder.java
@@ -0,0 +1,43 @@
+package co.nstant.in.cbor.decoder;
+
+import java.io.InputStream;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.HalfPrecisionFloat;
+
+public class HalfPrecisionFloatDecoder extends
+ AbstractDecoder<HalfPrecisionFloat> {
+
+ public HalfPrecisionFloatDecoder(CborDecoder decoder,
+ InputStream inputStream) {
+ super(decoder, inputStream);
+ }
+
+ @Override
+ public HalfPrecisionFloat decode(int initialByte) throws CborException {
+ int bits = nextSymbol() << 8 | nextSymbol();
+ return new HalfPrecisionFloat(toFloat(bits));
+ }
+
+ /**
+ * @see http://stackoverflow.com/a/5684578
+ */
+ private static float toFloat(int bits) {
+ int s = (bits & 0x8000) >> 15;
+ int e = (bits & 0x7C00) >> 10;
+ int f = bits & 0x03FF;
+
+ if (e == 0) {
+ return (float) ((s != 0 ? -1 : 1) * Math.pow(2, -14) * (f / Math
+ .pow(2, 10)));
+ } else if (e == 0x1F) {
+ return f != 0 ? Float.NaN
+ : (s != 0 ? -1 : 1) * Float.POSITIVE_INFINITY;
+ }
+
+ return (float) ((s != 0 ? -1 : 1) * Math.pow(2, e - 15) * (1 + f / Math
+ .pow(2, 10)));
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/decoder/MapDecoder.java b/src/main/java/co/nstant/in/cbor/decoder/MapDecoder.java
new file mode 100644
index 0000000..f30023f
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/decoder/MapDecoder.java
@@ -0,0 +1,65 @@
+package co.nstant.in.cbor.decoder;
+
+import java.io.InputStream;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Map;
+import co.nstant.in.cbor.model.Special;
+
+public class MapDecoder extends AbstractDecoder<Map> {
+
+ public MapDecoder(CborDecoder decoder, InputStream inputStream) {
+ super(decoder, inputStream);
+ }
+
+ @Override
+ public Map decode(int initialByte) throws CborException {
+ long length = getLength(initialByte);
+ if (length == INFINITY) {
+ return decodeInfinitiveLength();
+ } else {
+ return decodeFixedLength(length);
+ }
+ }
+
+ private Map decodeInfinitiveLength() throws CborException {
+ Map map = new Map();
+ map.setChunked(true);
+ if (decoder.isAutoDecodeInfinitiveMaps()) {
+ for (;;) {
+ DataItem key = decoder.decodeNext();
+ if (Special.BREAK.equals(key)) {
+ break;
+ }
+ DataItem value = decoder.decodeNext();
+ if (key == null || value == null) {
+ throw new CborException("Unexpected end of stream");
+ }
+ if (decoder.isRejectDuplicateKeys() && map.get(key) != null) {
+ throw new CborException("Duplicate key found in map");
+ }
+ map.put(key, value);
+ }
+ }
+ return map;
+ }
+
+ private Map decodeFixedLength(long length) throws CborException {
+ Map map = new Map((int) length);
+ for (long i = 0; i < length; i++) {
+ DataItem key = decoder.decodeNext();
+ DataItem value = decoder.decodeNext();
+ if (key == null || value == null) {
+ throw new CborException("Unexpected end of stream");
+ }
+ if (decoder.isRejectDuplicateKeys() && map.get(key) != null) {
+ throw new CborException("Duplicate key found in map");
+ }
+ map.put(key, value);
+ }
+ return map;
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/decoder/NegativeIntegerDecoder.java b/src/main/java/co/nstant/in/cbor/decoder/NegativeIntegerDecoder.java
new file mode 100644
index 0000000..72ebd6a
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/decoder/NegativeIntegerDecoder.java
@@ -0,0 +1,23 @@
+package co.nstant.in.cbor.decoder;
+
+import java.io.InputStream;
+import java.math.BigInteger;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.NegativeInteger;
+
+public class NegativeIntegerDecoder extends AbstractDecoder<NegativeInteger> {
+
+ private static final BigInteger MINUS_ONE = BigInteger.valueOf(-1);
+
+ public NegativeIntegerDecoder(CborDecoder decoder, InputStream inputStream) {
+ super(decoder, inputStream);
+ }
+
+ @Override
+ public NegativeInteger decode(int initialByte) throws CborException {
+ return new NegativeInteger(MINUS_ONE.subtract(getLengthAsBigInteger(initialByte)));
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/decoder/SinglePrecisionFloatDecoder.java b/src/main/java/co/nstant/in/cbor/decoder/SinglePrecisionFloatDecoder.java
new file mode 100644
index 0000000..a87d984
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/decoder/SinglePrecisionFloatDecoder.java
@@ -0,0 +1,28 @@
+package co.nstant.in.cbor.decoder;
+
+import java.io.InputStream;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.SinglePrecisionFloat;
+
+public class SinglePrecisionFloatDecoder extends AbstractDecoder<SinglePrecisionFloat> {
+
+ public SinglePrecisionFloatDecoder(CborDecoder decoder, InputStream inputStream) {
+ super(decoder, inputStream);
+ }
+
+ @Override
+ public SinglePrecisionFloat decode(int initialByte) throws CborException {
+ int bits = 0;
+ bits |= nextSymbol() & 0xFF;
+ bits <<= 8;
+ bits |= nextSymbol() & 0xFF;
+ bits <<= 8;
+ bits |= nextSymbol() & 0xFF;
+ bits <<= 8;
+ bits |= nextSymbol() & 0xFF;
+ return new SinglePrecisionFloat(Float.intBitsToFloat(bits));
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/decoder/SpecialDecoder.java b/src/main/java/co/nstant/in/cbor/decoder/SpecialDecoder.java
new file mode 100644
index 0000000..bab71e7
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/decoder/SpecialDecoder.java
@@ -0,0 +1,60 @@
+package co.nstant.in.cbor.decoder;
+
+import java.io.InputStream;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.SimpleValue;
+import co.nstant.in.cbor.model.SimpleValueType;
+import co.nstant.in.cbor.model.Special;
+import co.nstant.in.cbor.model.SpecialType;
+
+public class SpecialDecoder extends AbstractDecoder<Special> {
+
+ private final HalfPrecisionFloatDecoder halfPrecisionFloatDecoder;
+ private final SinglePrecisionFloatDecoder singlePrecisionFloatDecoder;
+ private final DoublePrecisionFloatDecoder doublePrecisionFloatDecoder;
+
+ public SpecialDecoder(CborDecoder decoder, InputStream inputStream) {
+ super(decoder, inputStream);
+ this.halfPrecisionFloatDecoder = new HalfPrecisionFloatDecoder(decoder, inputStream);
+ this.singlePrecisionFloatDecoder = new SinglePrecisionFloatDecoder(decoder, inputStream);
+ this.doublePrecisionFloatDecoder = new DoublePrecisionFloatDecoder(decoder, inputStream);
+ }
+
+ @Override
+ public Special decode(int initialByte) throws CborException {
+ switch (SpecialType.ofByte(initialByte)) {
+ case BREAK:
+ return Special.BREAK;
+ case SIMPLE_VALUE:
+ switch (SimpleValueType.ofByte(initialByte)) {
+ case FALSE:
+ return SimpleValue.FALSE;
+ case TRUE:
+ return SimpleValue.TRUE;
+ case NULL:
+ return SimpleValue.NULL;
+ case UNDEFINED:
+ return SimpleValue.UNDEFINED;
+ case UNALLOCATED:
+ return new SimpleValue(initialByte & 31);
+ case RESERVED:
+ default:
+ throw new CborException("Not implemented");
+ }
+ case IEEE_754_HALF_PRECISION_FLOAT:
+ return halfPrecisionFloatDecoder.decode(initialByte);
+ case IEEE_754_SINGLE_PRECISION_FLOAT:
+ return singlePrecisionFloatDecoder.decode(initialByte);
+ case IEEE_754_DOUBLE_PRECISION_FLOAT:
+ return doublePrecisionFloatDecoder.decode(initialByte);
+ case SIMPLE_VALUE_NEXT_BYTE:
+ return new SimpleValue(nextSymbol());
+ case UNALLOCATED:
+ default:
+ throw new CborException("Not implemented");
+ }
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/decoder/TagDecoder.java b/src/main/java/co/nstant/in/cbor/decoder/TagDecoder.java
new file mode 100644
index 0000000..f8cd86e
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/decoder/TagDecoder.java
@@ -0,0 +1,20 @@
+package co.nstant.in.cbor.decoder;
+
+import java.io.InputStream;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.Tag;
+
+public class TagDecoder extends AbstractDecoder<Tag> {
+
+ public TagDecoder(CborDecoder decoder, InputStream inputStream) {
+ super(decoder, inputStream);
+ }
+
+ @Override
+ public Tag decode(int initialByte) throws CborException {
+ return new Tag(getLength(initialByte));
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/decoder/UnicodeStringDecoder.java b/src/main/java/co/nstant/in/cbor/decoder/UnicodeStringDecoder.java
new file mode 100644
index 0000000..18bb8ba
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/decoder/UnicodeStringDecoder.java
@@ -0,0 +1,65 @@
+package co.nstant.in.cbor.decoder;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.MajorType;
+import co.nstant.in.cbor.model.Special;
+import co.nstant.in.cbor.model.UnicodeString;
+
+public class UnicodeStringDecoder extends AbstractDecoder<UnicodeString> {
+
+ public UnicodeStringDecoder(CborDecoder decoder, InputStream inputStream) {
+ super(decoder, inputStream);
+ }
+
+ @Override
+ public UnicodeString decode(int initialByte) throws CborException {
+ long length = getLength(initialByte);
+ if (length == INFINITY) {
+ if (decoder.isAutoDecodeInfinitiveUnicodeStrings()) {
+ return decodeInfinitiveLength();
+ } else {
+ UnicodeString unicodeString = new UnicodeString(null);
+ unicodeString.setChunked(true);
+ return unicodeString;
+ }
+ } else {
+ return decodeFixedLength(length);
+ }
+ }
+
+ private UnicodeString decodeInfinitiveLength() throws CborException {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ for (;;) {
+ DataItem dataItem = decoder.decodeNext();
+ if (dataItem == null) {
+ throw new CborException("Unexpected end of stream");
+ }
+ MajorType majorType = dataItem.getMajorType();
+ if (Special.BREAK.equals(dataItem)) {
+ break;
+ } else if (majorType == MajorType.UNICODE_STRING) {
+ UnicodeString unicodeString = (UnicodeString) dataItem;
+ byte[] byteArray = unicodeString.toString().getBytes(StandardCharsets.UTF_8);
+ bytes.write(byteArray, 0, byteArray.length);
+ } else {
+ throw new CborException("Unexpected major type " + majorType);
+ }
+ }
+ return new UnicodeString(new String(bytes.toByteArray(), StandardCharsets.UTF_8));
+ }
+
+ private UnicodeString decodeFixedLength(long length) throws CborException {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream((int) length);
+ for (long i = 0; i < length; i++) {
+ bytes.write(nextSymbol());
+ }
+ return new UnicodeString(new String(bytes.toByteArray(), StandardCharsets.UTF_8));
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/decoder/UnsignedIntegerDecoder.java b/src/main/java/co/nstant/in/cbor/decoder/UnsignedIntegerDecoder.java
new file mode 100644
index 0000000..922cf60
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/decoder/UnsignedIntegerDecoder.java
@@ -0,0 +1,20 @@
+package co.nstant.in.cbor.decoder;
+
+import java.io.InputStream;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.UnsignedInteger;
+
+public class UnsignedIntegerDecoder extends AbstractDecoder<UnsignedInteger> {
+
+ public UnsignedIntegerDecoder(CborDecoder decoder, InputStream inputStream) {
+ super(decoder, inputStream);
+ }
+
+ @Override
+ public UnsignedInteger decode(int initialByte) throws CborException {
+ return new UnsignedInteger(getLengthAsBigInteger(initialByte));
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/encoder/AbstractEncoder.java b/src/main/java/co/nstant/in/cbor/encoder/AbstractEncoder.java
new file mode 100644
index 0000000..9a2ad13
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/encoder/AbstractEncoder.java
@@ -0,0 +1,131 @@
+package co.nstant.in.cbor.encoder;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.AdditionalInformation;
+import co.nstant.in.cbor.model.ByteString;
+import co.nstant.in.cbor.model.MajorType;
+import co.nstant.in.cbor.model.Tag;
+
+public abstract class AbstractEncoder<T> {
+
+ private final OutputStream outputStream;
+ protected final CborEncoder encoder;
+
+ public AbstractEncoder(CborEncoder encoder, OutputStream outputStream) {
+ this.encoder = encoder;
+ this.outputStream = outputStream;
+ }
+
+ public abstract void encode(T dataItem) throws CborException;
+
+ protected void encodeTypeChunked(MajorType majorType) throws CborException {
+ int symbol = majorType.getValue() << 5;
+ symbol |= AdditionalInformation.INDEFINITE.getValue();
+ try {
+ outputStream.write(symbol);
+ } catch (IOException ioException) {
+ throw new CborException(ioException);
+ }
+ }
+
+ protected void encodeTypeAndLength(MajorType majorType, long length) throws CborException {
+ int symbol = majorType.getValue() << 5;
+ if (length <= 23L) {
+ write((int) (symbol | length));
+ } else if (length <= 255L) {
+ symbol |= AdditionalInformation.ONE_BYTE.getValue();
+ write(symbol);
+ write((int) length);
+ } else if (length <= 65535L) {
+ symbol |= AdditionalInformation.TWO_BYTES.getValue();
+ write(symbol);
+ write((int) (length >> 8));
+ write((int) (length & 0xFF));
+ } else if (length <= 4294967295L) {
+ symbol |= AdditionalInformation.FOUR_BYTES.getValue();
+ write(symbol);
+ write((int) ((length >> 24) & 0xFF));
+ write((int) ((length >> 16) & 0xFF));
+ write((int) ((length >> 8) & 0xFF));
+ write((int) (length & 0xFF));
+ } else {
+ symbol |= AdditionalInformation.EIGHT_BYTES.getValue();
+ write(symbol);
+ write((int) ((length >> 56) & 0xFF));
+ write((int) ((length >> 48) & 0xFF));
+ write((int) ((length >> 40) & 0xFF));
+ write((int) ((length >> 32) & 0xFF));
+ write((int) ((length >> 24) & 0xFF));
+ write((int) ((length >> 16) & 0xFF));
+ write((int) ((length >> 8) & 0xFF));
+ write((int) (length & 0xFF));
+ }
+ }
+
+ protected void encodeTypeAndLength(MajorType majorType, BigInteger length) throws CborException {
+ boolean negative = majorType == MajorType.NEGATIVE_INTEGER;
+ int symbol = majorType.getValue() << 5;
+ if (length.compareTo(BigInteger.valueOf(24)) == -1) {
+ write(symbol | length.intValue());
+ } else if (length.compareTo(BigInteger.valueOf(256)) == -1) {
+ symbol |= AdditionalInformation.ONE_BYTE.getValue();
+ write(symbol);
+ write(length.intValue());
+ } else if (length.compareTo(BigInteger.valueOf(65536L)) == -1) {
+ symbol |= AdditionalInformation.TWO_BYTES.getValue();
+ write(symbol);
+ long twoByteValue = length.longValue();
+ write((int) (twoByteValue >> 8));
+ write((int) (twoByteValue & 0xFF));
+ } else if (length.compareTo(BigInteger.valueOf(4294967296L)) == -1) {
+ symbol |= AdditionalInformation.FOUR_BYTES.getValue();
+ write(symbol);
+ long fourByteValue = length.longValue();
+ write((int) ((fourByteValue >> 24) & 0xFF));
+ write((int) ((fourByteValue >> 16) & 0xFF));
+ write((int) ((fourByteValue >> 8) & 0xFF));
+ write((int) (fourByteValue & 0xFF));
+ } else if (length.compareTo(new BigInteger("18446744073709551616")) == -1) {
+ symbol |= AdditionalInformation.EIGHT_BYTES.getValue();
+ write(symbol);
+ BigInteger mask = BigInteger.valueOf(0xFF);
+ write(length.shiftRight(56).and(mask).intValue());
+ write(length.shiftRight(48).and(mask).intValue());
+ write(length.shiftRight(40).and(mask).intValue());
+ write(length.shiftRight(32).and(mask).intValue());
+ write(length.shiftRight(24).and(mask).intValue());
+ write(length.shiftRight(16).and(mask).intValue());
+ write(length.shiftRight(8).and(mask).intValue());
+ write(length.and(mask).intValue());
+ } else {
+ if (negative) {
+ encoder.encode(new Tag(3));
+ } else {
+ encoder.encode(new Tag(2));
+ }
+ encoder.encode(new ByteString(length.toByteArray()));
+ }
+ }
+
+ protected void write(int b) throws CborException {
+ try {
+ outputStream.write(b);
+ } catch (IOException ioException) {
+ throw new CborException(ioException);
+ }
+ }
+
+ protected void write(byte[] bytes) throws CborException {
+ try {
+ outputStream.write(bytes);
+ } catch (IOException ioException) {
+ throw new CborException(ioException);
+ }
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/encoder/ArrayEncoder.java b/src/main/java/co/nstant/in/cbor/encoder/ArrayEncoder.java
new file mode 100644
index 0000000..ae0ddbe
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/encoder/ArrayEncoder.java
@@ -0,0 +1,31 @@
+package co.nstant.in.cbor.encoder;
+
+import java.io.OutputStream;
+import java.util.List;
+
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.Array;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.MajorType;
+
+public class ArrayEncoder extends AbstractEncoder<Array> {
+
+ public ArrayEncoder(CborEncoder encoder, OutputStream outputStream) {
+ super(encoder, outputStream);
+ }
+
+ @Override
+ public void encode(Array array) throws CborException {
+ List<DataItem> dataItems = array.getDataItems();
+ if (array.isChunked()) {
+ encodeTypeChunked(MajorType.ARRAY);
+ } else {
+ encodeTypeAndLength(MajorType.ARRAY, dataItems.size());
+ }
+ for (DataItem dataItem : dataItems) {
+ encoder.encode(dataItem);
+ }
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/encoder/ByteStringEncoder.java b/src/main/java/co/nstant/in/cbor/encoder/ByteStringEncoder.java
new file mode 100644
index 0000000..6c1ca19
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/encoder/ByteStringEncoder.java
@@ -0,0 +1,33 @@
+package co.nstant.in.cbor.encoder;
+
+import java.io.OutputStream;
+
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.ByteString;
+import co.nstant.in.cbor.model.MajorType;
+import co.nstant.in.cbor.model.SimpleValue;
+
+public class ByteStringEncoder extends AbstractEncoder<ByteString> {
+
+ public ByteStringEncoder(CborEncoder encoder, OutputStream outputStream) {
+ super(encoder, outputStream);
+ }
+
+ @Override
+ public void encode(ByteString byteString) throws CborException {
+ byte[] bytes = byteString.getBytes();
+ if (byteString.isChunked()) {
+ encodeTypeChunked(MajorType.BYTE_STRING);
+ if (bytes != null) {
+ encode(new ByteString(bytes));
+ }
+ } else if (bytes == null) {
+ encoder.encode(SimpleValue.NULL);
+ } else {
+ encodeTypeAndLength(MajorType.BYTE_STRING, bytes.length);
+ write(bytes);
+ }
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/encoder/DoublePrecisionFloatEncoder.java b/src/main/java/co/nstant/in/cbor/encoder/DoublePrecisionFloatEncoder.java
new file mode 100644
index 0000000..5e09369
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/encoder/DoublePrecisionFloatEncoder.java
@@ -0,0 +1,29 @@
+package co.nstant.in.cbor.encoder;
+
+import java.io.OutputStream;
+
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DoublePrecisionFloat;
+
+public class DoublePrecisionFloatEncoder extends AbstractEncoder<DoublePrecisionFloat> {
+
+ public DoublePrecisionFloatEncoder(CborEncoder encoder, OutputStream outputStream) {
+ super(encoder, outputStream);
+ }
+
+ @Override
+ public void encode(DoublePrecisionFloat dataItem) throws CborException {
+ write((7 << 5) | 27);
+ long bits = Double.doubleToRawLongBits(dataItem.getValue());
+ write((int) ((bits >> 56) & 0xFF));
+ write((int) ((bits >> 48) & 0xFF));
+ write((int) ((bits >> 40) & 0xFF));
+ write((int) ((bits >> 32) & 0xFF));
+ write((int) ((bits >> 24) & 0xFF));
+ write((int) ((bits >> 16) & 0xFF));
+ write((int) ((bits >> 8) & 0xFF));
+ write((int) ((bits >> 0) & 0xFF));
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/encoder/HalfPrecisionFloatEncoder.java b/src/main/java/co/nstant/in/cbor/encoder/HalfPrecisionFloatEncoder.java
new file mode 100644
index 0000000..13ec12f
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/encoder/HalfPrecisionFloatEncoder.java
@@ -0,0 +1,58 @@
+package co.nstant.in.cbor.encoder;
+
+import java.io.OutputStream;
+
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.HalfPrecisionFloat;
+
+public class HalfPrecisionFloatEncoder extends AbstractEncoder<HalfPrecisionFloat> {
+
+ public HalfPrecisionFloatEncoder(CborEncoder encoder, OutputStream outputStream) {
+ super(encoder, outputStream);
+ }
+
+ @Override
+ public void encode(HalfPrecisionFloat dataItem) throws CborException {
+ write((7 << 5) | 25);
+ int bits = fromFloat(dataItem.getValue());
+ write((bits >> 8) & 0xFF);
+ write((bits >> 0) & 0xFF);
+ }
+
+ /**
+ * @see <a href="http://stackoverflow.com/a/6162687">Stack Overflow</a>
+ */
+
+ // returns all higher 16 bits as 0 for all results
+ public static int fromFloat(float fval) {
+ int fbits = Float.floatToIntBits(fval);
+ int sign = fbits >>> 16 & 0x8000; // sign only
+ int val = 0x1000 + fbits & 0x7fffffff; // rounded value
+
+ if (val >= 0x47800000) // might be or become NaN/Inf
+ { // avoid Inf due to rounding
+ if ((fbits & 0x7fffffff) >= 0x47800000) { // is or must become
+ // NaN/Inf
+ if (val < 0x7f800000) {// was value but too large
+ return sign | 0x7c00; // make it +/-Inf
+ }
+ return sign | 0x7c00 | // remains +/-Inf or NaN
+ (fbits & 0x007fffff) >>> 13; // keep NaN (and
+ // Inf) bits
+ }
+ return sign | 0x7bff; // unrounded not quite Inf
+ }
+ if (val >= 0x38800000) { // remains normalized value
+ return sign | val - 0x38000000 >>> 13; // exp - 127 + 15
+ }
+ if (val < 0x33000000) { // too small for subnormal
+ return sign; // becomes +/-0
+ }
+ val = (fbits & 0x7fffffff) >>> 23; // tmp exp for subnormal calc
+ return sign | ((fbits & 0x7fffff | 0x800000) // add subnormal bit
+ + (0x800000 >>> val - 102) // round depending on cut off
+ >>> 126 - val); // div by 2^(1-(exp-127+15)) and >> 13 | exp=0
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/encoder/MapEncoder.java b/src/main/java/co/nstant/in/cbor/encoder/MapEncoder.java
new file mode 100644
index 0000000..bbf79be
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/encoder/MapEncoder.java
@@ -0,0 +1,100 @@
+package co.nstant.in.cbor.encoder;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.TreeMap;
+
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.MajorType;
+import co.nstant.in.cbor.model.Map;
+import co.nstant.in.cbor.model.SimpleValue;
+
+public class MapEncoder extends AbstractEncoder<Map> {
+
+ public MapEncoder(CborEncoder encoder, OutputStream outputStream) {
+ super(encoder, outputStream);
+ }
+
+ @Override
+ public void encode(Map map) throws CborException {
+ Collection<DataItem> keys = map.getKeys();
+
+ if (map.isChunked()) {
+ encodeTypeChunked(MajorType.MAP);
+ } else {
+ encodeTypeAndLength(MajorType.MAP, keys.size());
+ }
+
+ if (keys.isEmpty()) {
+ return;
+ }
+
+ if (map.isChunked()) {
+ for (DataItem key : keys) {
+ encoder.encode(key);
+ encoder.encode(map.get(key));
+ }
+ encoder.encode(SimpleValue.BREAK);
+ return;
+ }
+
+ /**
+ * The keys in every map must be sorted lowest value to highest. Sorting
+ * is performed on the bytes of the representation of the key data items
+ * without paying attention to the 3/5 bit splitting for major types.
+ * (Note that this rule allows maps that have keys of different types,
+ * even though that is probably a bad practice that could lead to errors
+ * in some canonicalization implementations.) The sorting rules are:
+ *
+ * If two keys have different lengths, the shorter one sorts earlier;
+ *
+ * If two keys have the same length, the one with the lower value in
+ * (byte-wise) lexical order sorts earlier.
+ */
+
+ TreeMap<byte[], byte[]> sortedMap = new TreeMap<>(new Comparator<byte[]>() {
+
+ @Override
+ public int compare(byte[] o1, byte[] o2) {
+ if (o1.length < o2.length) {
+ return -1;
+ }
+ if (o1.length > o2.length) {
+ return 1;
+ }
+ for (int i = 0; i < o1.length; i++) {
+ if (o1[i] < o2[i]) {
+ return -1;
+ }
+ if (o1[i] > o2[i]) {
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ });
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ CborEncoder e = new CborEncoder(byteArrayOutputStream);
+ for (DataItem key : keys) {
+ // Key
+ e.encode(key);
+ byte[] keyBytes = byteArrayOutputStream.toByteArray();
+ byteArrayOutputStream.reset();
+ // Value
+ e.encode(map.get(key));
+ byte[] valueBytes = byteArrayOutputStream.toByteArray();
+ byteArrayOutputStream.reset();
+ sortedMap.put(keyBytes, valueBytes);
+ }
+ for (java.util.Map.Entry<byte[], byte[]> entry : sortedMap.entrySet()) {
+ write(entry.getKey());
+ write(entry.getValue());
+ }
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/encoder/NegativeIntegerEncoder.java b/src/main/java/co/nstant/in/cbor/encoder/NegativeIntegerEncoder.java
new file mode 100644
index 0000000..b078fee
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/encoder/NegativeIntegerEncoder.java
@@ -0,0 +1,24 @@
+package co.nstant.in.cbor.encoder;
+
+import java.io.OutputStream;
+import java.math.BigInteger;
+
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.MajorType;
+import co.nstant.in.cbor.model.NegativeInteger;
+
+public class NegativeIntegerEncoder extends AbstractEncoder<NegativeInteger> {
+
+ private static final BigInteger MINUS_ONE = BigInteger.valueOf(-1);
+
+ public NegativeIntegerEncoder(CborEncoder encoder, OutputStream outputStream) {
+ super(encoder, outputStream);
+ }
+
+ @Override
+ public void encode(NegativeInteger dataItem) throws CborException {
+ encodeTypeAndLength(MajorType.NEGATIVE_INTEGER, MINUS_ONE.subtract(dataItem.getValue()).abs());
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/encoder/SinglePrecisionFloatEncoder.java b/src/main/java/co/nstant/in/cbor/encoder/SinglePrecisionFloatEncoder.java
new file mode 100644
index 0000000..820562e
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/encoder/SinglePrecisionFloatEncoder.java
@@ -0,0 +1,25 @@
+package co.nstant.in.cbor.encoder;
+
+import java.io.OutputStream;
+
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.SinglePrecisionFloat;
+
+public class SinglePrecisionFloatEncoder extends AbstractEncoder<SinglePrecisionFloat> {
+
+ public SinglePrecisionFloatEncoder(CborEncoder encoder, OutputStream outputStream) {
+ super(encoder, outputStream);
+ }
+
+ @Override
+ public void encode(SinglePrecisionFloat dataItem) throws CborException {
+ write((7 << 5) | 26);
+ int bits = Float.floatToRawIntBits(dataItem.getValue());
+ write((bits >> 24) & 0xFF);
+ write((bits >> 16) & 0xFF);
+ write((bits >> 8) & 0xFF);
+ write((bits >> 0) & 0xFF);
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/encoder/SpecialEncoder.java b/src/main/java/co/nstant/in/cbor/encoder/SpecialEncoder.java
new file mode 100644
index 0000000..b00eb99
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/encoder/SpecialEncoder.java
@@ -0,0 +1,81 @@
+package co.nstant.in.cbor.encoder;
+
+import java.io.OutputStream;
+
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DoublePrecisionFloat;
+import co.nstant.in.cbor.model.HalfPrecisionFloat;
+import co.nstant.in.cbor.model.SimpleValue;
+import co.nstant.in.cbor.model.SimpleValueType;
+import co.nstant.in.cbor.model.SinglePrecisionFloat;
+import co.nstant.in.cbor.model.Special;
+
+public class SpecialEncoder extends AbstractEncoder<Special> {
+
+ private final HalfPrecisionFloatEncoder halfPrecisionFloatEncoder;
+ private final SinglePrecisionFloatEncoder singlePrecisionFloatEncoder;
+ private final DoublePrecisionFloatEncoder doublePrecisionFloatEncoder;
+
+ public SpecialEncoder(CborEncoder encoder, OutputStream outputStream) {
+ super(encoder, outputStream);
+ halfPrecisionFloatEncoder = new HalfPrecisionFloatEncoder(encoder, outputStream);
+ singlePrecisionFloatEncoder = new SinglePrecisionFloatEncoder(encoder, outputStream);
+ doublePrecisionFloatEncoder = new DoublePrecisionFloatEncoder(encoder, outputStream);
+ }
+
+ @Override
+ public void encode(Special dataItem) throws CborException {
+ switch (dataItem.getSpecialType()) {
+ case BREAK:
+ write((7 << 5) | 31);
+ break;
+ case SIMPLE_VALUE:
+ SimpleValue simpleValue = (SimpleValue) dataItem;
+ switch (simpleValue.getSimpleValueType()) {
+ case FALSE:
+ case NULL:
+ case TRUE:
+ case UNDEFINED:
+ SimpleValueType type = simpleValue.getSimpleValueType();
+ write((7 << 5) | type.getValue());
+ break;
+ case UNALLOCATED:
+ write((7 << 5) | simpleValue.getValue());
+ break;
+ case RESERVED:
+ break;
+ }
+ break;
+ case UNALLOCATED:
+ throw new CborException("Unallocated special type");
+ case IEEE_754_HALF_PRECISION_FLOAT:
+ if (!(dataItem instanceof HalfPrecisionFloat)) {
+ throw new CborException("Wrong data item type");
+ }
+ halfPrecisionFloatEncoder.encode((HalfPrecisionFloat) dataItem);
+ break;
+ case IEEE_754_SINGLE_PRECISION_FLOAT:
+ if (!(dataItem instanceof SinglePrecisionFloat)) {
+ throw new CborException("Wrong data item type");
+ }
+ singlePrecisionFloatEncoder.encode((SinglePrecisionFloat) dataItem);
+ break;
+ case IEEE_754_DOUBLE_PRECISION_FLOAT:
+ if (!(dataItem instanceof DoublePrecisionFloat)) {
+ throw new CborException("Wrong data item type");
+ }
+ doublePrecisionFloatEncoder.encode((DoublePrecisionFloat) dataItem);
+ break;
+ case SIMPLE_VALUE_NEXT_BYTE:
+ if (!(dataItem instanceof SimpleValue)) {
+ throw new CborException("Wrong data item type");
+ }
+ SimpleValue simpleValueNextByte = (SimpleValue) dataItem;
+ write((7 << 5) | 24);
+ write(simpleValueNextByte.getValue());
+ break;
+ }
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/encoder/TagEncoder.java b/src/main/java/co/nstant/in/cbor/encoder/TagEncoder.java
new file mode 100644
index 0000000..be9948e
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/encoder/TagEncoder.java
@@ -0,0 +1,21 @@
+package co.nstant.in.cbor.encoder;
+
+import java.io.OutputStream;
+
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.MajorType;
+import co.nstant.in.cbor.model.Tag;
+
+public class TagEncoder extends AbstractEncoder<Tag> {
+
+ public TagEncoder(CborEncoder encoder, OutputStream outputStream) {
+ super(encoder, outputStream);
+ }
+
+ @Override
+ public void encode(Tag tag) throws CborException {
+ encodeTypeAndLength(MajorType.TAG, tag.getValue());
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/encoder/UnicodeStringEncoder.java b/src/main/java/co/nstant/in/cbor/encoder/UnicodeStringEncoder.java
new file mode 100644
index 0000000..ef769cb
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/encoder/UnicodeStringEncoder.java
@@ -0,0 +1,36 @@
+package co.nstant.in.cbor.encoder;
+
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.MajorType;
+import co.nstant.in.cbor.model.SimpleValue;
+import co.nstant.in.cbor.model.UnicodeString;
+
+public class UnicodeStringEncoder extends AbstractEncoder<UnicodeString> {
+
+ public UnicodeStringEncoder(CborEncoder encoder, OutputStream outputStream) {
+ super(encoder, outputStream);
+ }
+
+ @Override
+ public void encode(UnicodeString dataItem) throws CborException {
+ String string = dataItem.getString();
+ if (dataItem.isChunked()) {
+ encodeTypeChunked(MajorType.UNICODE_STRING);
+ if (string != null) {
+ encode(new UnicodeString(string));
+ }
+ } else if (string == null) {
+ encoder.encode(SimpleValue.NULL);
+ } else {
+ byte[] bytes;
+ bytes = string.getBytes(StandardCharsets.UTF_8);
+ encodeTypeAndLength(MajorType.UNICODE_STRING, bytes.length);
+ write(bytes);
+ }
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/encoder/UnsignedIntegerEncoder.java b/src/main/java/co/nstant/in/cbor/encoder/UnsignedIntegerEncoder.java
new file mode 100644
index 0000000..c7d08ef
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/encoder/UnsignedIntegerEncoder.java
@@ -0,0 +1,21 @@
+package co.nstant.in.cbor.encoder;
+
+import java.io.OutputStream;
+
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.MajorType;
+import co.nstant.in.cbor.model.UnsignedInteger;
+
+public class UnsignedIntegerEncoder extends AbstractEncoder<UnsignedInteger> {
+
+ public UnsignedIntegerEncoder(CborEncoder encoder, OutputStream outputStream) {
+ super(encoder, outputStream);
+ }
+
+ @Override
+ public void encode(UnsignedInteger dataItem) throws CborException {
+ encodeTypeAndLength(MajorType.UNSIGNED_INTEGER, dataItem.getValue());
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/AbstractFloat.java b/src/main/java/co/nstant/in/cbor/model/AbstractFloat.java
new file mode 100644
index 0000000..5766e9a
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/AbstractFloat.java
@@ -0,0 +1,32 @@
+package co.nstant.in.cbor.model;
+
+import java.util.Objects;
+
+public class AbstractFloat extends Special {
+
+ private final float value;
+
+ public AbstractFloat(SpecialType specialType, float value) {
+ super(specialType);
+ this.value = value;
+ }
+
+ public float getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof AbstractFloat) {
+ AbstractFloat other = (AbstractFloat) object;
+ return super.equals(object) && value == other.value;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode() ^ Objects.hashCode(value);
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/AdditionalInformation.java b/src/main/java/co/nstant/in/cbor/model/AdditionalInformation.java
new file mode 100644
index 0000000..23a014d
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/AdditionalInformation.java
@@ -0,0 +1,55 @@
+package co.nstant.in.cbor.model;
+
+/**
+ * The initial byte of each data item contains both information about the major
+ * type (the high-order 3 bits) and additional information (the low-order 5
+ * bits). When the value of the additional information is less than 24, it is
+ * directly used as a small unsigned integer. When it is 24 to 27, the
+ * additional bytes for a variable-length integer immediately follow; the values
+ * 24 to 27 of the additional information specify that its length is a 1-, 2-,
+ * 4- or 8-byte unsigned integer, respectively. Additional information value 31
+ * is used for indefinite length items, described in Section 2.2. Additional
+ * information values 28 to 30 are reserved for future expansion.
+ */
+public enum AdditionalInformation {
+
+ DIRECT(0), // 0-23
+ ONE_BYTE(24), // 24
+ TWO_BYTES(25), // 25
+ FOUR_BYTES(26), // 26
+ EIGHT_BYTES(27), // 27
+ RESERVED(28), // 28-30
+ INDEFINITE(31); // 31
+
+ private final int value;
+
+ private AdditionalInformation(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public static AdditionalInformation ofByte(int b) {
+ switch (b & 31) {
+ case 24:
+ return ONE_BYTE;
+ case 25:
+ return TWO_BYTES;
+ case 26:
+ return FOUR_BYTES;
+ case 27:
+ return EIGHT_BYTES;
+ case 28:
+ case 29:
+ case 30:
+ return RESERVED;
+ case 31:
+ return INDEFINITE;
+ default:
+ return DIRECT;
+ }
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/Array.java b/src/main/java/co/nstant/in/cbor/model/Array.java
new file mode 100644
index 0000000..2c36861
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/Array.java
@@ -0,0 +1,49 @@
+package co.nstant.in.cbor.model;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class Array extends ChunkableDataItem {
+
+ private final ArrayList<DataItem> objects;
+
+ public Array() {
+ super(MajorType.ARRAY);
+ objects = new ArrayList<>();
+ }
+
+ public Array add(DataItem object) {
+ objects.add(object);
+ return this;
+ }
+
+ public List<DataItem> getDataItems() {
+ return objects;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof Array) {
+ Array other = (Array) object;
+ return super.equals(object) && objects.equals(other.objects);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode() ^ objects.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder stringBuilder = new StringBuilder("[");
+ if (isChunked()) {
+ stringBuilder.append("_ ");
+ }
+ stringBuilder.append(Arrays.toString(objects.toArray()).substring(1));
+ return stringBuilder.toString();
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/ByteString.java b/src/main/java/co/nstant/in/cbor/model/ByteString.java
new file mode 100644
index 0000000..be7b598
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/ByteString.java
@@ -0,0 +1,40 @@
+package co.nstant.in.cbor.model;
+
+import java.util.Arrays;
+
+public class ByteString extends ChunkableDataItem {
+
+ private final byte[] bytes;
+
+ public ByteString(byte[] bytes) {
+ super(MajorType.BYTE_STRING);
+ if (bytes == null) {
+ this.bytes = null;
+ } else {
+ this.bytes = bytes;
+ }
+ }
+
+ public byte[] getBytes() {
+ if (bytes == null) {
+ return null;
+ } else {
+ return bytes;
+ }
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof ByteString) {
+ ByteString other = (ByteString) object;
+ return super.equals(object) && Arrays.equals(bytes, other.bytes);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode() ^ Arrays.hashCode(bytes);
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/ChunkableDataItem.java b/src/main/java/co/nstant/in/cbor/model/ChunkableDataItem.java
new file mode 100644
index 0000000..cd01de9
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/ChunkableDataItem.java
@@ -0,0 +1,36 @@
+package co.nstant.in.cbor.model;
+
+import java.util.Objects;
+
+class ChunkableDataItem extends DataItem {
+
+ private boolean chunked = false;
+
+ protected ChunkableDataItem(MajorType majorType) {
+ super(majorType);
+ }
+
+ public boolean isChunked() {
+ return chunked;
+ }
+
+ public ChunkableDataItem setChunked(boolean chunked) {
+ this.chunked = chunked;
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof ChunkableDataItem) {
+ ChunkableDataItem other = (ChunkableDataItem) object;
+ return super.equals(object) && chunked == other.chunked;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode() ^ Objects.hashCode(chunked);
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/DataItem.java b/src/main/java/co/nstant/in/cbor/model/DataItem.java
new file mode 100644
index 0000000..4cecf76
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/DataItem.java
@@ -0,0 +1,69 @@
+package co.nstant.in.cbor.model;
+
+import java.util.Objects;
+
+public class DataItem {
+
+ private final MajorType majorType;
+ private Tag tag;
+
+ protected DataItem(MajorType majorType) {
+ this.majorType = majorType;
+ Objects.requireNonNull(majorType, "majorType is null");
+ }
+
+ public MajorType getMajorType() {
+ return majorType;
+ }
+
+ public void setTag(int tag) {
+ if (tag < 0) {
+ throw new IllegalArgumentException("tag number must be 0 or greater");
+ }
+
+ this.tag = new Tag(tag);
+ }
+
+ public void setTag(Tag tag) {
+ Objects.requireNonNull(tag, "tag is null");
+ this.tag = tag;
+ }
+
+ public void removeTag() {
+ tag = null;
+ }
+
+ public Tag getTag() {
+ return tag;
+ }
+
+ public boolean hasTag() {
+ return tag != null;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof DataItem) {
+ DataItem other = (DataItem) object;
+ if (tag != null) {
+ return tag.equals(other.tag) && majorType == other.majorType;
+ } else {
+ return other.tag == null && majorType == other.majorType;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(majorType, tag);
+ }
+
+ protected void assertTrue(boolean condition, String message) {
+ if (!condition) {
+ throw new IllegalArgumentException(message);
+ }
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/DoublePrecisionFloat.java b/src/main/java/co/nstant/in/cbor/model/DoublePrecisionFloat.java
new file mode 100644
index 0000000..3a6da94
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/DoublePrecisionFloat.java
@@ -0,0 +1,37 @@
+package co.nstant.in.cbor.model;
+
+import java.util.Objects;
+
+public class DoublePrecisionFloat extends Special {
+
+ private final double value;
+
+ public DoublePrecisionFloat(double value) {
+ super(SpecialType.IEEE_754_DOUBLE_PRECISION_FLOAT);
+ this.value = value;
+ }
+
+ public double getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof DoublePrecisionFloat) {
+ DoublePrecisionFloat other = (DoublePrecisionFloat) object;
+ return super.equals(object) && value == other.value;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode() ^ Objects.hashCode(value);
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(value);
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/HalfPrecisionFloat.java b/src/main/java/co/nstant/in/cbor/model/HalfPrecisionFloat.java
new file mode 100644
index 0000000..ca33d62
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/HalfPrecisionFloat.java
@@ -0,0 +1,9 @@
+package co.nstant.in.cbor.model;
+
+public class HalfPrecisionFloat extends AbstractFloat {
+
+ public HalfPrecisionFloat(float value) {
+ super(SpecialType.IEEE_754_HALF_PRECISION_FLOAT, value);
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/LanguageTaggedString.java b/src/main/java/co/nstant/in/cbor/model/LanguageTaggedString.java
new file mode 100644
index 0000000..f54667d
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/LanguageTaggedString.java
@@ -0,0 +1,28 @@
+package co.nstant.in.cbor.model;
+
+import java.util.Objects;
+
+/**
+ * See https://peteroupc.github.io/CBOR/langtags.html
+ */
+public class LanguageTaggedString extends Array {
+
+ public LanguageTaggedString(String language, String string) {
+ this(new UnicodeString(language), new UnicodeString(string));
+ }
+
+ public LanguageTaggedString(UnicodeString language, UnicodeString string) {
+ setTag(38);
+ add(Objects.requireNonNull(language));
+ add(Objects.requireNonNull(string));
+ }
+
+ public UnicodeString getLanguage() {
+ return (UnicodeString) getDataItems().get(0);
+ }
+
+ public UnicodeString getString() {
+ return (UnicodeString) getDataItems().get(1);
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/MajorType.java b/src/main/java/co/nstant/in/cbor/model/MajorType.java
new file mode 100644
index 0000000..e970b45
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/MajorType.java
@@ -0,0 +1,126 @@
+package co.nstant.in.cbor.model;
+
+public enum MajorType {
+
+ INVALID(-1),
+
+ /**
+ * Major type 0: an unsigned integer. The 5-bit additional information is
+ * either the integer itself (for additional information values 0 through
+ * 23), or the length of additional data. Additional information 24 means
+ * the value is represented in an additional uint8_t, 25 means a uint16_t,
+ * 26 means a uint32_t, and 27 means a uint64_t. For example, the integer 10
+ * is denoted as the one byte 0b000_01010 (major type 0, additional
+ * information 10). The integer 500 would be 0b000_11001 (major type 0,
+ * additional information 25) followed by the two bytes 0x01f4, which is 500
+ * in decimal.
+ */
+ UNSIGNED_INTEGER(0),
+
+ /**
+ * Major type 1: a negative integer. The encoding follows the rules for
+ * unsigned integers (major type 0), except that the value is then -1 minus
+ * the encoded unsigned integer. For example, the integer -500 would be
+ * 0b001_11001 (major type 1, additional information 25) followed by the two
+ * bytes 0x01f3, which is 499 in decimal.
+ */
+ NEGATIVE_INTEGER(1),
+
+ /**
+ * Major type 2: a byte string. The string's length in bytes is represented
+ * following the rules for positive integers (major type 0). For example, a
+ * byte string whose length is 5 would have an initial byte of 0b010_00101
+ * (major type 2, additional information 5 for the length), followed by 5
+ * bytes of binary content. A byte string whose length is 500 would have 3
+ * initial bytes of 0b010_11001 (major type 2, additional information 25 to
+ * indicate a two-byte length) followed by the two bytes 0x01f4 for a length
+ * of 500, followed by 500 bytes of binary content.
+ */
+ BYTE_STRING(2),
+
+ /**
+ * Major type 3: string of Unicode characters that is encoded as UTF-8
+ * [RFC3629]. The format of this type is identical to that of byte strings
+ * (major type 2), that is, as with major type 2, the length gives the
+ * number of bytes. This type is provided for systems that need to interpret
+ * or display human-readable text. In contrast to formats such as JSON, the
+ * Unicode characters in this type are never escaped. Thus, a newline
+ * character (U+000A) is always represented in a string as the byte 0x0a,
+ * and never as the bytes 0x5c6e (the characters "\" and "n") or as
+ * 0x5c7530303061 (the characters "\", "u", "0", "0", "0", and "a").
+ */
+ UNICODE_STRING(3),
+
+ /**
+ * Major type 4: an array of data items. Arrays are also called lists,
+ * sequences, or tuples. The array's length follows the rules for byte
+ * strings (major type 2), except that the length denotes the number of data
+ * items, not the length in bytes that the array takes up. Items in an array
+ * do not need to all be of the same type. For example, an array that
+ * contains 10 items of any type would have an initial byte of 0b100_01010
+ * (major type of 4, additional information of 10 for the length) followed
+ * by the 10 remaining items.
+ */
+ ARRAY(4),
+
+ /**
+ * Major type 5: a map of pairs of data items. Maps are also called tables,
+ * dictionaries, hashes, or objects (in JSON). A map is comprised of pairs
+ * of data items, the even-numbered ones serving as keys and the following
+ * odd-numbered ones serving as values for the key that comes immediately
+ * before it. The map's length follows the rules for byte strings (major
+ * type 2), except that the length denotes the number of pairs, not the
+ * length in bytes that the map takes up. For example, a map that contains 9
+ * pairs would have an initial byte of 0b101_01001 (major type of 5,
+ * additional information of 9 for the number of pairs) followed by the 18
+ * remaining items. The first item is the first key, the second item is the
+ * first value, the third item is the second key, and so on.
+ */
+ MAP(5),
+
+ /**
+ * Major type 6: optional semantic tagging of other major types. See Section
+ * 2.4.
+ */
+ TAG(6),
+
+ /**
+ * Major type 7: floating point numbers and simple data types that need no
+ * content, as well as the "break" stop code. See Section 2.3.
+ */
+ SPECIAL(7);
+
+ private final int value;
+
+ private MajorType(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public static MajorType ofByte(int b) {
+ switch (b >> 5) {
+ case 0:
+ return UNSIGNED_INTEGER;
+ case 1:
+ return NEGATIVE_INTEGER;
+ case 2:
+ return BYTE_STRING;
+ case 3:
+ return UNICODE_STRING;
+ case 4:
+ return ARRAY;
+ case 5:
+ return MAP;
+ case 6:
+ return TAG;
+ case 7:
+ return SPECIAL;
+ default:
+ return INVALID;
+ }
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/Map.java b/src/main/java/co/nstant/in/cbor/model/Map.java
new file mode 100644
index 0000000..153ae0d
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/Map.java
@@ -0,0 +1,79 @@
+package co.nstant.in.cbor.model;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+public class Map extends ChunkableDataItem {
+
+ private final HashMap<DataItem, DataItem> map;
+ private final List<DataItem> keys = new LinkedList<>();
+
+ public Map() {
+ super(MajorType.MAP);
+ map = new HashMap<>();
+ }
+
+ public Map(int initialCapacity) {
+ super(MajorType.MAP);
+ map = new HashMap<>(initialCapacity);
+ }
+
+ public Map put(DataItem key, DataItem value) {
+ if (map.put(key, value) == null) {
+ keys.add(key);
+ }
+ return this;
+ }
+
+ public DataItem get(DataItem key) {
+ return map.get(key);
+ }
+
+ public DataItem remove(DataItem key) {
+ keys.remove(key);
+ return map.remove(key);
+ }
+
+ public Collection<DataItem> getKeys() {
+ return keys;
+ }
+
+ public Collection<DataItem> getValues() {
+ return map.values();
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof Map) {
+ Map other = (Map) object;
+ return super.equals(object) && map.equals(other.map);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode() ^ map.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder stringBuilder = new StringBuilder();
+ if (isChunked()) {
+ stringBuilder.append("{_ ");
+ } else {
+ stringBuilder.append("{ ");
+ }
+ for (DataItem key : keys) {
+ stringBuilder.append(key).append(": ").append(map.get(key)).append(", ");
+ }
+ if (stringBuilder.toString().endsWith(", ")) {
+ stringBuilder.setLength(stringBuilder.length() - 2);
+ }
+ stringBuilder.append(" }");
+ return stringBuilder.toString();
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/NegativeInteger.java b/src/main/java/co/nstant/in/cbor/model/NegativeInteger.java
new file mode 100644
index 0000000..12f320f
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/NegativeInteger.java
@@ -0,0 +1,16 @@
+package co.nstant.in.cbor.model;
+
+import java.math.BigInteger;
+
+public class NegativeInteger extends Number {
+
+ public NegativeInteger(long value) {
+ this(BigInteger.valueOf(value));
+ assertTrue(value < 0L, "value " + value + " is not < 0");
+ }
+
+ public NegativeInteger(BigInteger value) {
+ super(MajorType.NEGATIVE_INTEGER, value);
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/Number.java b/src/main/java/co/nstant/in/cbor/model/Number.java
new file mode 100644
index 0000000..a018852
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/Number.java
@@ -0,0 +1,38 @@
+package co.nstant.in.cbor.model;
+
+import java.math.BigInteger;
+import java.util.Objects;
+
+public abstract class Number extends DataItem {
+
+ private final BigInteger value;
+
+ protected Number(MajorType majorType, BigInteger value) {
+ super(majorType);
+ this.value = Objects.requireNonNull(value);
+ }
+
+ public BigInteger getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof Number) {
+ Number other = (Number) object;
+ return super.equals(object) && value.equals(other.value);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode() ^ value.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return value.toString();
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/RationalNumber.java b/src/main/java/co/nstant/in/cbor/model/RationalNumber.java
new file mode 100644
index 0000000..0ddd937
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/RationalNumber.java
@@ -0,0 +1,36 @@
+package co.nstant.in.cbor.model;
+
+import java.math.BigInteger;
+
+import co.nstant.in.cbor.CborException;
+
+/**
+ * Rational Numbers: http://peteroupc.github.io/CBOR/rational.html
+ */
+
+public class RationalNumber extends Array {
+
+ public RationalNumber(Number numerator, Number denominator) throws CborException {
+ setTag(30);
+ if (numerator == null) {
+ throw new CborException("Numerator is null");
+ }
+ if (denominator == null) {
+ throw new CborException("Denominator is null");
+ }
+ if (denominator.getValue().equals(BigInteger.ZERO)) {
+ throw new CborException("Denominator is zero");
+ }
+ add(numerator);
+ add(denominator);
+ }
+
+ public Number getNumerator() {
+ return (Number) getDataItems().get(0);
+ }
+
+ public Number getDenominator() {
+ return (Number) getDataItems().get(1);
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/SimpleValue.java b/src/main/java/co/nstant/in/cbor/model/SimpleValue.java
new file mode 100644
index 0000000..1a02fc9
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/SimpleValue.java
@@ -0,0 +1,58 @@
+package co.nstant.in.cbor.model;
+
+import java.util.Objects;
+
+public class SimpleValue extends Special {
+
+ private final SimpleValueType simpleValueType;
+
+ public static final SimpleValue FALSE = new SimpleValue(
+ SimpleValueType.FALSE);
+ public static final SimpleValue TRUE = new SimpleValue(SimpleValueType.TRUE);
+ public static final SimpleValue NULL = new SimpleValue(SimpleValueType.NULL);
+ public static final SimpleValue UNDEFINED = new SimpleValue(
+ SimpleValueType.UNDEFINED);
+
+ private final int value;
+
+ public SimpleValue(SimpleValueType simpleValueType) {
+ super(SpecialType.SIMPLE_VALUE);
+ this.value = simpleValueType.getValue();
+ this.simpleValueType = simpleValueType;
+ }
+
+ public SimpleValue(int value) {
+ super(value <= 23 ? SpecialType.SIMPLE_VALUE
+ : SpecialType.SIMPLE_VALUE_NEXT_BYTE);
+ this.value = value;
+ this.simpleValueType = SimpleValueType.ofByte(value);
+ }
+
+ public SimpleValueType getSimpleValueType() {
+ return simpleValueType;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof SimpleValue) {
+ SimpleValue other = (SimpleValue) object;
+ return super.equals(object) && value == other.value;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode() ^ Objects.hashCode(value);
+ }
+
+ @Override
+ public String toString() {
+ return simpleValueType.toString();
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/SimpleValueType.java b/src/main/java/co/nstant/in/cbor/model/SimpleValueType.java
new file mode 100644
index 0000000..f450abe
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/SimpleValueType.java
@@ -0,0 +1,46 @@
+package co.nstant.in.cbor.model;
+
+public enum SimpleValueType {
+
+ FALSE(20),
+ TRUE(21),
+ NULL(22),
+ UNDEFINED(23),
+ RESERVED(0),
+ UNALLOCATED(0);
+
+ private final int value;
+
+ private SimpleValueType(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public static SimpleValueType ofByte(int b) {
+ switch (b & 31) {
+ case 20:
+ return FALSE;
+ case 21:
+ return TRUE;
+ case 22:
+ return NULL;
+ case 23:
+ return UNDEFINED;
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ return RESERVED;
+ default:
+ return UNALLOCATED;
+ }
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/SinglePrecisionFloat.java b/src/main/java/co/nstant/in/cbor/model/SinglePrecisionFloat.java
new file mode 100644
index 0000000..d28b016
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/SinglePrecisionFloat.java
@@ -0,0 +1,9 @@
+package co.nstant.in.cbor.model;
+
+public class SinglePrecisionFloat extends AbstractFloat {
+
+ public SinglePrecisionFloat(float value) {
+ super(SpecialType.IEEE_754_SINGLE_PRECISION_FLOAT, value);
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/Special.java b/src/main/java/co/nstant/in/cbor/model/Special.java
new file mode 100644
index 0000000..365950b
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/Special.java
@@ -0,0 +1,39 @@
+package co.nstant.in.cbor.model;
+
+import java.util.Objects;
+
+public class Special extends DataItem {
+
+ public static final Special BREAK = new Special(SpecialType.BREAK);
+
+ private final SpecialType specialType;
+
+ protected Special(SpecialType specialType) {
+ super(MajorType.SPECIAL);
+ this.specialType = Objects.requireNonNull(specialType);
+ }
+
+ public SpecialType getSpecialType() {
+ return specialType;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof Special) {
+ Special other = (Special) object;
+ return super.equals(object) && specialType == other.specialType;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode() ^ Objects.hashCode(specialType);
+ }
+
+ @Override
+ public String toString() {
+ return specialType.name();
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/SpecialType.java b/src/main/java/co/nstant/in/cbor/model/SpecialType.java
new file mode 100644
index 0000000..9c99537
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/SpecialType.java
@@ -0,0 +1,34 @@
+package co.nstant.in.cbor.model;
+
+public enum SpecialType {
+
+ SIMPLE_VALUE,
+ SIMPLE_VALUE_NEXT_BYTE,
+ IEEE_754_HALF_PRECISION_FLOAT,
+ IEEE_754_SINGLE_PRECISION_FLOAT,
+ IEEE_754_DOUBLE_PRECISION_FLOAT,
+ UNALLOCATED,
+ BREAK;
+
+ public static SpecialType ofByte(int b) {
+ switch (b & 31) {
+ case 24:
+ return SIMPLE_VALUE_NEXT_BYTE;
+ case 25:
+ return IEEE_754_HALF_PRECISION_FLOAT;
+ case 26:
+ return IEEE_754_SINGLE_PRECISION_FLOAT;
+ case 27:
+ return IEEE_754_DOUBLE_PRECISION_FLOAT;
+ case 28:
+ case 29:
+ case 30:
+ return UNALLOCATED;
+ case 31:
+ return BREAK;
+ default:
+ return SIMPLE_VALUE;
+ }
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/Tag.java b/src/main/java/co/nstant/in/cbor/model/Tag.java
new file mode 100644
index 0000000..507d81a
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/Tag.java
@@ -0,0 +1,37 @@
+package co.nstant.in.cbor.model;
+
+import java.util.Objects;
+
+public class Tag extends DataItem {
+
+ private final long value;
+
+ public Tag(long value) {
+ super(MajorType.TAG);
+ this.value = value;
+ }
+
+ public long getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof Tag) {
+ Tag other = (Tag) object;
+ return super.equals(object) && value == other.value;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode() ^ Objects.hashCode(value);
+ }
+
+ @Override
+ public String toString() {
+ return "Tag("+value+")";
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/UnicodeString.java b/src/main/java/co/nstant/in/cbor/model/UnicodeString.java
new file mode 100644
index 0000000..b2bf0bf
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/UnicodeString.java
@@ -0,0 +1,50 @@
+package co.nstant.in.cbor.model;
+
+public class UnicodeString extends ChunkableDataItem {
+
+ private final String string;
+
+ public UnicodeString(String string) {
+ super(MajorType.UNICODE_STRING);
+ this.string = string;
+ }
+
+ @Override
+ public String toString() {
+ if (string == null) {
+ return "null";
+ } else {
+ return string;
+ }
+ }
+
+ public String getString() {
+ return string;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof UnicodeString && super.equals(object)) {
+ UnicodeString other = (UnicodeString) object;
+ if (string == null) {
+ return other.string == null;
+ } else {
+ return string.equals(other.string);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 0;
+
+ if (string != null) {
+ hash = super.hashCode();
+ hash += string.hashCode();
+ }
+
+ return hash;
+ }
+
+}
diff --git a/src/main/java/co/nstant/in/cbor/model/UnsignedInteger.java b/src/main/java/co/nstant/in/cbor/model/UnsignedInteger.java
new file mode 100644
index 0000000..e547760
--- /dev/null
+++ b/src/main/java/co/nstant/in/cbor/model/UnsignedInteger.java
@@ -0,0 +1,16 @@
+package co.nstant.in.cbor.model;
+
+import java.math.BigInteger;
+
+public class UnsignedInteger extends Number {
+
+ public UnsignedInteger(long value) {
+ this(BigInteger.valueOf(value));
+ assertTrue(value >= 0L, "value " + value + " is not >= 0");
+ }
+
+ public UnsignedInteger(BigInteger value) {
+ super(MajorType.UNSIGNED_INTEGER, value);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/CborBuilderTest.java b/src/test/java/co/nstant/in/cbor/CborBuilderTest.java
new file mode 100644
index 0000000..1c58e6e
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/CborBuilderTest.java
@@ -0,0 +1,34 @@
+package co.nstant.in.cbor;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Tag;
+
+public class CborBuilderTest {
+
+ @Test
+ public void shouldResetDataItems() {
+ CborBuilder builder = new CborBuilder();
+ builder.add(true);
+ builder.add(1.0f);
+ assertEquals(2, builder.build().size());
+ builder.reset();
+ assertEquals(0, builder.build().size());
+ }
+
+ @Test
+ public void shouldAddTag() {
+ CborBuilder builder = new CborBuilder();
+ List<DataItem> dataItems = builder.addTag(1234).build();
+ assertEquals(1, dataItems.size());
+ assertTrue(dataItems.get(0) instanceof Tag);
+ assertEquals(1234, ((Tag) dataItems.get(0)).getValue());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/CborEncoderTest.java b/src/test/java/co/nstant/in/cbor/CborEncoderTest.java
new file mode 100644
index 0000000..060a90e
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/CborEncoderTest.java
@@ -0,0 +1,33 @@
+package co.nstant.in.cbor;
+
+import java.io.ByteArrayOutputStream;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.MajorType;
+
+public class CborEncoderTest {
+
+ private class InvalidDataItem extends DataItem {
+
+ public InvalidDataItem() {
+ super(MajorType.INVALID);
+ }
+
+ }
+
+ private CborEncoder encoder;
+
+ @Before
+ public void setup() {
+ encoder = new CborEncoder(new ByteArrayOutputStream());
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldNotEncodeInvalidMajorType() throws CborException {
+ encoder.encode(new InvalidDataItem());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/CborExceptionTest.java b/src/test/java/co/nstant/in/cbor/CborExceptionTest.java
new file mode 100644
index 0000000..1ae974b
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/CborExceptionTest.java
@@ -0,0 +1,29 @@
+package co.nstant.in.cbor;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class CborExceptionTest {
+
+ @Test
+ public void shouldHaveMessage() {
+ CborException cborException = new CborException("message");
+ Assert.assertEquals("message", cborException.getMessage());
+ }
+
+ @Test
+ public void shouldHaveThrowable() {
+ Throwable throwable = new Throwable();
+ CborException cborException = new CborException(throwable);
+ Assert.assertEquals(throwable, cborException.getCause());
+ }
+
+ @Test
+ public void shouldHaveMessageAndThrowable() {
+ Throwable throwable = new Throwable();
+ CborException cborException = new CborException("message", throwable);
+ Assert.assertEquals("message", cborException.getMessage());
+ Assert.assertEquals(throwable, cborException.getCause());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/DatemItemListenerTest.java b/src/test/java/co/nstant/in/cbor/DatemItemListenerTest.java
new file mode 100644
index 0000000..daec312
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/DatemItemListenerTest.java
@@ -0,0 +1,35 @@
+package co.nstant.in.cbor;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.UnsignedInteger;
+
+public class DatemItemListenerTest {
+
+ @Test
+ public void shouldDecodeZero() throws CborException {
+ final int[] dataItems = new int[1];
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ new CborEncoder(outputStream).encode(new CborBuilder().add(1234).build());
+ new CborDecoder(new ByteArrayInputStream(outputStream.toByteArray())).decode(new DataItemListener() {
+
+ @Override
+ public void onDataItem(DataItem dataItem) {
+ synchronized (dataItems) {
+ ++dataItems[0];
+ }
+ assertTrue(dataItem instanceof UnsignedInteger);
+ }
+
+ });
+ assertEquals(1, dataItems[0]);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/EncoderDecoderTest.java b/src/test/java/co/nstant/in/cbor/EncoderDecoderTest.java
new file mode 100644
index 0000000..bbac324
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/EncoderDecoderTest.java
@@ -0,0 +1,45 @@
+package co.nstant.in.cbor;
+
+import java.io.ByteArrayOutputStream;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.NegativeInteger;
+import co.nstant.in.cbor.model.UnsignedInteger;
+
+public class EncoderDecoderTest {
+
+ @Test
+ public void test() throws CborException {
+ UnsignedInteger a = new UnsignedInteger(1);
+ NegativeInteger x = new NegativeInteger(-2);
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteArrayOutputStream);
+ encoder.encode(a);
+ encoder.encode(x);
+ byte[] bytes = byteArrayOutputStream.toByteArray();
+ DataItem object = CborDecoder.decode(bytes).get(0);
+ Assert.assertEquals(a, object);
+ }
+
+ @Test
+ public void testTagging() throws CborException {
+ UnsignedInteger a = new UnsignedInteger(1);
+ NegativeInteger x = new NegativeInteger(-2);
+
+ a.setTag(1);
+
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteArrayOutputStream);
+ encoder.encode(a);
+ encoder.encode(x);
+ byte[] bytes = byteArrayOutputStream.toByteArray();
+ DataItem object = CborDecoder.decode(bytes).get(0);
+ Assert.assertEquals(a, object);
+ Assert.assertTrue(object.hasTag());
+ Assert.assertEquals(1L, object.getTag().getValue());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/builder/AbstractBuilderTest.java b/src/test/java/co/nstant/in/cbor/builder/AbstractBuilderTest.java
new file mode 100644
index 0000000..01a4194
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/builder/AbstractBuilderTest.java
@@ -0,0 +1,75 @@
+package co.nstant.in.cbor.builder;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.OutputStream;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.encoder.HalfPrecisionFloatEncoder;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.HalfPrecisionFloat;
+import co.nstant.in.cbor.model.SinglePrecisionFloat;
+
+public class AbstractBuilderTest {
+
+ private class TestBuilder extends AbstractBuilder<Object> {
+
+ private boolean encoderThrowsException = false;
+
+ public TestBuilder() {
+ super(null);
+ }
+
+ public DataItem testConvert(float value) {
+ return convert(value);
+ }
+
+ public void testAddChunk() {
+ addChunk(null);
+ }
+
+ public void setEncoderThrowsException() {
+ encoderThrowsException = true;
+ }
+
+ @Override
+ protected HalfPrecisionFloatEncoder getHalfPrecisionFloatEncoder(OutputStream outputStream) {
+ if (encoderThrowsException) {
+ return new HalfPrecisionFloatEncoder(null, outputStream) {
+ @Override
+ public void encode(HalfPrecisionFloat dataItem) throws CborException {
+ throw new CborException("test");
+ }
+ };
+ } else {
+ return super.getHalfPrecisionFloatEncoder(outputStream);
+ }
+ }
+
+ }
+
+ @Test
+ public void shouldCallIsHalfPrecisionEnough() {
+ TestBuilder builder = new TestBuilder();
+ assertTrue(builder.testConvert(0.0f) instanceof HalfPrecisionFloat);
+ assertTrue(0.0f == ((HalfPrecisionFloat) builder.testConvert(0.0f)).getValue());
+ assertTrue(builder.testConvert(0.3f) instanceof SinglePrecisionFloat);
+ assertTrue(0.3f == ((SinglePrecisionFloat) builder.testConvert(0.3f)).getValue());
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void shouldThrowExceptionOnAddChunk() {
+ new TestBuilder().testAddChunk();
+ }
+
+ @Test
+ public void IsHalfPrecisionEnoughShallReturnFalseOnException() {
+ TestBuilder builder = new TestBuilder();
+ builder.setEncoderThrowsException();
+ assertTrue(builder.testConvert(0.0f) instanceof SinglePrecisionFloat);
+ assertTrue(0.0f == ((SinglePrecisionFloat) builder.testConvert(0.0f)).getValue());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/builder/ArrayBuilderTest.java b/src/test/java/co/nstant/in/cbor/builder/ArrayBuilderTest.java
new file mode 100644
index 0000000..9604f78
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/builder/ArrayBuilderTest.java
@@ -0,0 +1,78 @@
+package co.nstant.in.cbor.builder;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.model.Array;
+import co.nstant.in.cbor.model.ByteString;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.DoublePrecisionFloat;
+import co.nstant.in.cbor.model.HalfPrecisionFloat;
+import co.nstant.in.cbor.model.SimpleValue;
+
+public class ArrayBuilderTest {
+
+ @Test
+ public void shouldAddBoolean() {
+ CborBuilder builder = new CborBuilder();
+ List<DataItem> dataItems = builder.addArray()
+ .add(true)
+ .add(false)
+ .end()
+ .build();
+ assertEquals(1, dataItems.size());
+ assertTrue(dataItems.get(0) instanceof Array);
+ Array array = (Array) dataItems.get(0);
+ assertEquals(2, array.getDataItems().size());
+ assertTrue(array.getDataItems().get(0) instanceof SimpleValue);
+ assertTrue(array.getDataItems().get(1) instanceof SimpleValue);
+ }
+
+ @Test
+ public void shouldAddFloat() {
+ CborBuilder builder = new CborBuilder();
+ List<DataItem> dataItems = builder.addArray()
+ .add(1.0f)
+ .end()
+ .build();
+ assertEquals(1, dataItems.size());
+ assertTrue(dataItems.get(0) instanceof Array);
+ Array array = (Array) dataItems.get(0);
+ assertEquals(1, array.getDataItems().size());
+ assertTrue(array.getDataItems().get(0) instanceof HalfPrecisionFloat);
+ }
+
+ @Test
+ public void shouldAddDouble() {
+ CborBuilder builder = new CborBuilder();
+ List<DataItem> dataItems = builder.addArray()
+ .add(1.0d)
+ .end()
+ .build();
+ assertEquals(1, dataItems.size());
+ assertTrue(dataItems.get(0) instanceof Array);
+ Array array = (Array) dataItems.get(0);
+ assertEquals(1, array.getDataItems().size());
+ assertTrue(array.getDataItems().get(0) instanceof DoublePrecisionFloat);
+ }
+
+ @Test
+ public void shouldAddByteArray() {
+ CborBuilder builder = new CborBuilder();
+ List<DataItem> dataItems = builder.addArray()
+ .add(new byte[] { 0x0 })
+ .end()
+ .build();
+ assertEquals(1, dataItems.size());
+ assertTrue(dataItems.get(0) instanceof Array);
+ Array array = (Array) dataItems.get(0);
+ assertEquals(1, array.getDataItems().size());
+ assertTrue(array.getDataItems().get(0) instanceof ByteString);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/builder/MapBuilderTest.java b/src/test/java/co/nstant/in/cbor/builder/MapBuilderTest.java
new file mode 100644
index 0000000..d4c3407
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/builder/MapBuilderTest.java
@@ -0,0 +1,84 @@
+package co.nstant.in.cbor.builder;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.model.ByteString;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Map;
+import co.nstant.in.cbor.model.UnicodeString;
+import co.nstant.in.cbor.model.UnsignedInteger;
+
+public class MapBuilderTest {
+
+ @Test
+ public void testMapBuilder() {
+ CborBuilder builder = new CborBuilder();
+ List<DataItem> dataItems = builder.addMap()
+ .put(new UnicodeString("key"), new UnicodeString("value"))
+ .put(1, true)
+ .put(2, "value".getBytes())
+ .put(3, 1.0d)
+ .put(4, 1.0f)
+ .put(5, 1L)
+ .put(6, "value")
+ .put("7", true)
+ .put("8", "value".getBytes())
+ .put("9", 1.0d)
+ .put("10", 1.0f)
+ .put("11", 1L)
+ .put("12", "value")
+ .putMap(13)
+ .end()
+ .putMap("14")
+ .end()
+ .putMap(new UnsignedInteger(15))
+ .end()
+ .putArray(16)
+ .end()
+ .putArray("17")
+ .end()
+ .putArray(new UnsignedInteger(18))
+ .end()
+ .end()
+ .startMap()
+ .startArray(1).end()
+ .startArray(new UnsignedInteger(2)).end()
+ .end()
+ .build();
+ assertEquals(2, dataItems.size());
+ assertTrue(dataItems.get(0) instanceof Map);
+ Map map = (Map) dataItems.get(0);
+ assertEquals(19, map.getKeys().size());
+ }
+
+ @Test
+ public void startMapInMap() {
+ CborBuilder builder = new CborBuilder();
+ List<DataItem> dataItems = builder.addMap()
+ .startMap(new ByteString(new byte[] {0x01}))
+ .put(1, 2)
+ .end()
+ .startMap(1)
+ .end()
+ .startMap("asdf")
+ .end()
+ .end().build();
+ Map rootMap = (Map)dataItems.get(0);
+ DataItem keys[] = new DataItem[3];
+ rootMap.getKeys().toArray(keys);
+ assertEquals(keys[0], new ByteString(new byte[] {0x01}));
+ assertEquals(keys[1], new UnsignedInteger(1));
+ assertEquals(keys[2], new UnicodeString("asdf"));
+
+ assertTrue(rootMap.get(keys[0]) instanceof Map);
+ assertTrue(rootMap.get(keys[1]) instanceof Map);
+ assertTrue(rootMap.get(keys[2]) instanceof Map);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/decoder/AbstractDecoderTest.java b/src/test/java/co/nstant/in/cbor/decoder/AbstractDecoderTest.java
new file mode 100644
index 0000000..4a13f5d
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/decoder/AbstractDecoderTest.java
@@ -0,0 +1,105 @@
+package co.nstant.in.cbor.decoder;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.math.BigInteger;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.UnicodeString;
+
+public class AbstractDecoderTest {
+
+ private class TestableAbstractDecoder extends AbstractDecoder<UnicodeString> {
+
+ public TestableAbstractDecoder(InputStream inputStream) {
+ super(null, inputStream);
+ }
+
+ public void callNextSymbol() throws CborException {
+ nextSymbol();
+ }
+
+ public long callGetLength(int initialByte) throws CborException {
+ return getLength(initialByte);
+ }
+
+ public BigInteger callGetLengthAsBigInteger(int initialByte) throws CborException {
+ return getLengthAsBigInteger(initialByte);
+ }
+
+ @Override
+ public UnicodeString decode(int initialByte) throws CborException {
+ return null;
+ }
+
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowExceptionOnUnexpectedEndOfStream() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(new byte[] {});
+ new TestableAbstractDecoder(inputStream).callNextSymbol();
+ fail();
+ }
+
+ @Test
+ public void shouldDecodeInfinityLength() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(new byte[] {});
+ TestableAbstractDecoder decoder = new TestableAbstractDecoder(inputStream);
+ assertEquals(BigInteger.valueOf(-1), decoder.callGetLengthAsBigInteger(31));
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowExceptionOnReserved1() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(new byte[] {});
+ new TestableAbstractDecoder(inputStream).callGetLengthAsBigInteger(28);
+ fail();
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowExceptionOnReserved2() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(new byte[] {});
+ new TestableAbstractDecoder(inputStream).callGetLengthAsBigInteger(29);
+ fail();
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowExceptionOnReserved3() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(new byte[] {});
+ new TestableAbstractDecoder(inputStream).callGetLengthAsBigInteger(30);
+ fail();
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowExceptionOnReserved4() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(new byte[] {});
+ new TestableAbstractDecoder(inputStream).callGetLength(28);
+ fail();
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowExceptionOnReserved5() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(new byte[] {});
+ new TestableAbstractDecoder(inputStream).callGetLength(29);
+ fail();
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowExceptionOnReserved6() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(new byte[] {});
+ new TestableAbstractDecoder(inputStream).callGetLength(30);
+ fail();
+ }
+
+ @Test
+ public void shouldDecodeEightBytesLengthToLong() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(new byte[] { 1, 1, 1, 1, 1, 1, 1, 1 });
+ long value = new TestableAbstractDecoder(inputStream).callGetLength(27);
+ assertEquals(72340172838076673L, value);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/decoder/ArrayDecoderTest.java b/src/test/java/co/nstant/in/cbor/decoder/ArrayDecoderTest.java
new file mode 100644
index 0000000..8daa962
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/decoder/ArrayDecoderTest.java
@@ -0,0 +1,20 @@
+package co.nstant.in.cbor.decoder;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborException;
+
+public class ArrayDecoderTest {
+ @Test(expected = CborException.class)
+ public void shouldThrowOnIncompleteArray() throws CborException {
+ byte[] bytes = new byte[] {(byte) 0x82, 0x01 };
+ CborDecoder.decode(bytes);
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowInIncompleteIndefiniteLengthArray() throws CborException {
+ byte[] bytes = new byte[] {(byte) 0x9f, 0x01, 0x02};
+ CborDecoder.decode(bytes);
+ }
+}
diff --git a/src/test/java/co/nstant/in/cbor/decoder/ByteStringDecoderTest.java b/src/test/java/co/nstant/in/cbor/decoder/ByteStringDecoderTest.java
new file mode 100644
index 0000000..ffac44f
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/decoder/ByteStringDecoderTest.java
@@ -0,0 +1,76 @@
+package co.nstant.in.cbor.decoder;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+public class ByteStringDecoderTest {
+
+ @Test
+ public void shouldDecodeChunkedByteString() throws CborException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(baos);
+ encoder.encode(new CborBuilder()
+ .startByteString()
+ .add(new byte[] { '\0' })
+ .add(new byte[] { 0x10 })
+ .add(new byte[] { 0x13 })
+ .end()
+ .build());
+ byte[] encodedBytes = baos.toByteArray();
+ ByteArrayInputStream bais = new ByteArrayInputStream(encodedBytes);
+ CborDecoder decoder = new CborDecoder(bais);
+ List<DataItem> dataItems = decoder.decode();
+ assertNotNull(dataItems);
+ assertEquals(1, dataItems.size());
+ }
+
+ @Test
+ public void shouldDecodeByteString1K() throws CborException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(baos);
+ encoder.encode(new CborBuilder().add(new byte[1024]).build());
+ byte[] encodedBytes = baos.toByteArray();
+ ByteArrayInputStream bais = new ByteArrayInputStream(encodedBytes);
+ CborDecoder decoder = new CborDecoder(bais);
+ List<DataItem> dataItems = decoder.decode();
+ assertNotNull(dataItems);
+ assertEquals(1, dataItems.size());
+ }
+
+ @Test
+ public void shouldDecodeByteString1M() throws CborException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(baos);
+ encoder.encode(new CborBuilder().add(new byte[1024 * 1024]).build());
+ byte[] encodedBytes = baos.toByteArray();
+ ByteArrayInputStream bais = new ByteArrayInputStream(encodedBytes);
+ CborDecoder decoder = new CborDecoder(bais);
+ List<DataItem> dataItems = decoder.decode();
+ assertNotNull(dataItems);
+ assertEquals(1, dataItems.size());
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowOnIncompleteByteString() throws CborException {
+ byte[] bytes = new byte[] {0x42, 0x20};
+ CborDecoder.decode(bytes);
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldTrowOnMissingBreak() throws CborException {
+ byte[] bytes = new byte[] {0x5f, 0x41, 0x20};
+ CborDecoder.decode(bytes);
+ }
+}
diff --git a/src/test/java/co/nstant/in/cbor/decoder/CborDecoderTest.java b/src/test/java/co/nstant/in/cbor/decoder/CborDecoderTest.java
new file mode 100644
index 0000000..acf0313
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/decoder/CborDecoderTest.java
@@ -0,0 +1,179 @@
+package co.nstant.in.cbor.decoder;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.RationalNumber;
+import co.nstant.in.cbor.model.Tag;
+import co.nstant.in.cbor.model.UnsignedInteger;
+
+public class CborDecoderTest {
+
+ @Test(expected = CborException.class)
+ public void shouldThrowCborException() throws CborException {
+ CborDecoder cborDecoder = new CborDecoder(new InputStream() {
+
+ @Override
+ public int read() throws IOException {
+ throw new IOException();
+ }
+
+ });
+ cborDecoder.decodeNext();
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowCborException2() throws CborException {
+ CborDecoder cborDecoder = new CborDecoder(new InputStream() {
+
+ @Override
+ public int read() throws IOException {
+ return (8 << 5); // invalid major type
+ }
+
+ });
+ cborDecoder.decodeNext();
+ }
+
+ @Test
+ public void shouldSetAutoDecodeInfinitiveMaps() {
+ InputStream inputStream = new ByteArrayInputStream(new byte[] { 0, 1, 2 });
+ CborDecoder cborDecoder = new CborDecoder(inputStream);
+ assertTrue(cborDecoder.isAutoDecodeInfinitiveMaps());
+ cborDecoder.setAutoDecodeInfinitiveMaps(false);
+ assertFalse(cborDecoder.isAutoDecodeInfinitiveMaps());
+ }
+
+ @Test
+ public void shouldSetAutoDecodeRationalNumbers() {
+ InputStream inputStream = new ByteArrayInputStream(new byte[] { 0, 1, 2 });
+ CborDecoder cborDecoder = new CborDecoder(inputStream);
+ assertTrue(cborDecoder.isAutoDecodeRationalNumbers());
+ cborDecoder.setAutoDecodeRationalNumbers(false);
+ assertFalse(cborDecoder.isAutoDecodeRationalNumbers());
+ }
+
+ @Test
+ public void shouldSetAutoDecodeLanguageTaggedStrings() {
+ InputStream inputStream = new ByteArrayInputStream(new byte[] { 0, 1, 2 });
+ CborDecoder cborDecoder = new CborDecoder(inputStream);
+ assertTrue(cborDecoder.isAutoDecodeLanguageTaggedStrings());
+ cborDecoder.setAutoDecodeLanguageTaggedStrings(false);
+ assertFalse(cborDecoder.isAutoDecodeLanguageTaggedStrings());
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowOnRationalNumberDecode1() throws CborException {
+ List<DataItem> items = new CborBuilder()
+ .addTag(30)
+ .add(true)
+ .build();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(baos);
+ encoder.encode(items);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ CborDecoder decoder = new CborDecoder(bais);
+ decoder.decode();
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowOnRationalNumberDecode2() throws CborException {
+ List<DataItem> items = new CborBuilder()
+ .addTag(30)
+ .addArray().add(true).end()
+ .build();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(baos);
+ encoder.encode(items);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ CborDecoder decoder = new CborDecoder(bais);
+ decoder.decode();
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowOnRationalNumberDecode3() throws CborException {
+ List<DataItem> items = new CborBuilder()
+ .addTag(30)
+ .addArray().add(true).add(true).end()
+ .build();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(baos);
+ encoder.encode(items);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ CborDecoder decoder = new CborDecoder(bais);
+ decoder.decode();
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowOnRationalNumberDecode4() throws CborException {
+ List<DataItem> items = new CborBuilder()
+ .addTag(30)
+ .addArray().add(1).add(true).end()
+ .build();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(baos);
+ encoder.encode(items);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ CborDecoder decoder = new CborDecoder(bais);
+ decoder.decode();
+ }
+
+ @Test
+ public void shouldDecodeRationalNumber() throws CborException {
+ List<DataItem> items = new CborBuilder()
+ .addTag(30)
+ .addArray().add(1).add(2).end()
+ .build();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(baos);
+ encoder.encode(items);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ CborDecoder decoder = new CborDecoder(bais);
+ assertEquals(new RationalNumber(new UnsignedInteger(1), new UnsignedInteger(2)), decoder.decodeNext());
+ }
+
+ @Test
+ public void shouldDecodeTaggedTags() throws CborException {
+ DataItem decoded = CborDecoder.decode(new byte[] {(byte) 0xC1, (byte) 0xC2, 0x02}).get(0);
+
+ Tag outer = new Tag(1);
+ Tag inner = new Tag(2);
+ UnsignedInteger expected = new UnsignedInteger(2);
+ inner.setTag(outer);
+ expected.setTag(inner);
+
+ assertEquals(expected, decoded);
+ }
+
+ @Test
+ public void shouldDecodeTaggedRationalNumber() throws CborException {
+ List<DataItem> items = new CborBuilder()
+ .addTag(1)
+ .addTag(30)
+ .addArray().add(1).add(2).end()
+ .build();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(baos);
+ encoder.encode(items);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ CborDecoder decoder = new CborDecoder(bais);
+
+ RationalNumber expected = new RationalNumber(new UnsignedInteger(1), new UnsignedInteger(2));
+ expected.getTag().setTag(new Tag(1));
+ assertEquals(expected, decoder.decodeNext());
+ }
+}
diff --git a/src/test/java/co/nstant/in/cbor/decoder/LanguageTaggedStringDecoderTest.java b/src/test/java/co/nstant/in/cbor/decoder/LanguageTaggedStringDecoderTest.java
new file mode 100644
index 0000000..5523f60
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/decoder/LanguageTaggedStringDecoderTest.java
@@ -0,0 +1,104 @@
+package co.nstant.in.cbor.decoder;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.LanguageTaggedString;
+import co.nstant.in.cbor.model.UnicodeString;
+
+public class LanguageTaggedStringDecoderTest {
+
+ // Unexpected end of stream, tag without data item
+ @Test(expected = CborException.class)
+ public void shouldThrowException() throws CborException {
+ List<DataItem> items = new CborBuilder().addTag(38).build();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(baos);
+ encoder.encode(items);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ CborDecoder decoder = new CborDecoder(bais);
+ decoder.decode();
+ }
+
+ @Test(expected = CborException.class)
+ public void testExceptionOnNotAnArray() throws CborException {
+ List<DataItem> items = new CborBuilder()
+ .addTag(38)
+ .add(true)
+ .build();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(baos);
+ encoder.encode(items);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ CborDecoder decoder = new CborDecoder(bais);
+ decoder.decode();
+ }
+
+ @Test(expected = CborException.class)
+ public void testExceptionOnNot2ElementArray() throws CborException {
+ List<DataItem> items = new CborBuilder()
+ .addTag(38)
+ .addArray().add(true).end()
+ .build();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(baos);
+ encoder.encode(items);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ CborDecoder decoder = new CborDecoder(bais);
+ decoder.decode();
+ }
+
+ @Test(expected = CborException.class)
+ public void testExceptionOnNotFirstElementIsString() throws CborException {
+ List<DataItem> items = new CborBuilder()
+ .addTag(38)
+ .addArray().add(true).add(true).end()
+ .build();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(baos);
+ encoder.encode(items);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ CborDecoder decoder = new CborDecoder(bais);
+ decoder.decode();
+ }
+
+ @Test(expected = CborException.class)
+ public void testExceptionOnNotSecondElementIsString() throws CborException {
+ List<DataItem> items = new CborBuilder()
+ .addTag(38)
+ .addArray().add("en").add(true).end()
+ .build();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(baos);
+ encoder.encode(items);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ CborDecoder decoder = new CborDecoder(bais);
+ decoder.decode();
+ }
+
+ @Test
+ public void testDecoding() throws CborException {
+ List<DataItem> items = new CborBuilder()
+ .addTag(38)
+ .addArray().add("en").add("string").end()
+ .build();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(baos);
+ encoder.encode(items);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ CborDecoder decoder = new CborDecoder(bais);
+ DataItem item = decoder.decodeNext();
+ assertEquals(new LanguageTaggedString(new UnicodeString("en"), new UnicodeString("string")), item);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/decoder/MapDecoderTest.java b/src/test/java/co/nstant/in/cbor/decoder/MapDecoderTest.java
new file mode 100644
index 0000000..480625a
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/decoder/MapDecoderTest.java
@@ -0,0 +1,62 @@
+package co.nstant.in.cbor.decoder;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.util.List;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Map;
+import co.nstant.in.cbor.model.UnsignedInteger;
+
+public class MapDecoderTest {
+ @Test(expected = CborException.class)
+ public void shouldThrowOnMissingKeyInMap() throws CborException {
+ byte[] bytes = new byte[] {(byte) 0xa2, 0x01, 0x02};
+ CborDecoder.decode(bytes);
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowOnMissingValueInMap() throws CborException {
+ byte[] bytes = new byte[] {(byte) 0xa2, 0x01, 0x02, 0x03};
+ CborDecoder.decode(bytes);
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowOnIncompleteIndefiniteLengthMap() throws CborException {
+ byte[] bytes = new byte[] {(byte) 0xbf, 0x61, 0x01};
+ CborDecoder.decode(bytes);
+ }
+
+ @Test
+ public void shouldUseLastOfDuplicateKeysByDefault() throws CborException {
+ byte[] bytes = new byte[] {(byte)0xa2, 0x01, 0x01, 0x01, 0x02};
+ List<DataItem> decoded = CborDecoder.decode(bytes);
+ Map map = (Map)decoded.get(0);
+ assertEquals(map.getKeys().size(), 1);
+ assertEquals(map.get(new UnsignedInteger(1)), new UnsignedInteger(2));
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowOnDuplicateKeyIfEnabled() throws CborException {
+ byte[] bytes = new byte[] {(byte)0xa2, 0x01, 0x01, 0x01, 0x02};
+ ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ CborDecoder decoder = new CborDecoder(bais);
+ decoder.setRejectDuplicateKeys(true);
+ decoder.decode();
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowInDuplicateKeyInIndefiniteLengthMapIfEnabled()
+ throws CborException {
+ byte[] bytes = new byte[] {(byte)0xbf, 0x01, 0x01, 0x01, 0x02, (byte) 0xff};
+ ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ CborDecoder decoder = new CborDecoder(bais);
+ decoder.setRejectDuplicateKeys(true);
+ decoder.decode();
+ }
+}
diff --git a/src/test/java/co/nstant/in/cbor/decoder/SimpleValueDecoderTest.java b/src/test/java/co/nstant/in/cbor/decoder/SimpleValueDecoderTest.java
new file mode 100644
index 0000000..2c45973
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/decoder/SimpleValueDecoderTest.java
@@ -0,0 +1,61 @@
+package co.nstant.in.cbor.decoder;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.SimpleValue;
+import co.nstant.in.cbor.model.Special;
+
+public class SimpleValueDecoderTest {
+
+ @Test
+ public void shouldDecodeBoolean() throws CborException {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteArrayOutputStream);
+ encoder.encode(SimpleValue.TRUE);
+ encoder.encode(SimpleValue.FALSE);
+ byte[] encodedBytes = byteArrayOutputStream.toByteArray();
+ ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(encodedBytes);
+ List<DataItem> dataItems = new CborDecoder(byteArrayInputStream).decode();
+ int result = 0;
+ int position = 1;
+ for (DataItem dataItem : dataItems) {
+ position++;
+ switch (dataItem.getMajorType()) {
+ case SPECIAL:
+ Special special = (Special) dataItem;
+ switch (special.getSpecialType()) {
+ case SIMPLE_VALUE:
+ SimpleValue simpleValue = (SimpleValue) special;
+ switch (simpleValue.getSimpleValueType()) {
+ case FALSE:
+ result += position * 2;
+ break;
+ case TRUE:
+ result += position * 3;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ assertEquals(12, result);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/decoder/SpecialDecoderTest.java b/src/test/java/co/nstant/in/cbor/decoder/SpecialDecoderTest.java
new file mode 100644
index 0000000..0ea2d50
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/decoder/SpecialDecoderTest.java
@@ -0,0 +1,15 @@
+package co.nstant.in.cbor.decoder;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborException;
+
+public class SpecialDecoderTest {
+
+ @Test(expected = CborException.class)
+ public void shouldThrowExceptionOnUnallocated() throws CborException {
+ SpecialDecoder decoder = new SpecialDecoder(null, null);
+ decoder.decode(28);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/decoder/UnicodeStringDecoderTest.java b/src/test/java/co/nstant/in/cbor/decoder/UnicodeStringDecoderTest.java
new file mode 100644
index 0000000..b2fb038
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/decoder/UnicodeStringDecoderTest.java
@@ -0,0 +1,50 @@
+package co.nstant.in.cbor.decoder;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+public class UnicodeStringDecoderTest {
+
+ @Test
+ public void shouldDecodeChunkedUnicodeString() throws CborException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(baos);
+ encoder.encode(new CborBuilder()
+ .startString()
+ .add("foo")
+ .add("bar")
+ .end()
+ .build());
+ byte[] encodedBytes = baos.toByteArray();
+ ByteArrayInputStream bais = new ByteArrayInputStream(encodedBytes);
+ CborDecoder decoder = new CborDecoder(bais);
+ List<DataItem> dataItems = decoder.decode();
+ assertNotNull(dataItems);
+ assertEquals(1, dataItems.size());
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowOnIncompleteString() throws CborException {
+ byte[] bytes = new byte[] {0x62, 0x61};
+ CborDecoder.decode(bytes);
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowOnMissingBreak() throws CborException {
+ byte[] bytes = new byte[] {0x7f, 0x61, 0x61};
+ CborDecoder.decode(bytes);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/decoder/UnsignedIntegerDecoderTest.java b/src/test/java/co/nstant/in/cbor/decoder/UnsignedIntegerDecoderTest.java
new file mode 100644
index 0000000..058b9a5
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/decoder/UnsignedIntegerDecoderTest.java
@@ -0,0 +1,43 @@
+package co.nstant.in.cbor.decoder;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+import java.util.List;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.UnsignedInteger;
+
+public class UnsignedIntegerDecoderTest {
+
+ @Test
+ public void shouldDecodeBigNumbers() throws CborException {
+ BigInteger value = BigInteger.ONE;
+ for (int i = 1; i < 64; i++) {
+ value = value.shiftLeft(1);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(baos);
+ encoder.encode(new CborBuilder().add(value).build());
+ byte[] encodedBytes = baos.toByteArray();
+ ByteArrayInputStream bais = new ByteArrayInputStream(encodedBytes);
+ CborDecoder decoder = new CborDecoder(bais);
+ List<DataItem> dataItems = decoder.decode();
+ assertNotNull(dataItems);
+ assertEquals(1, dataItems.size());
+ DataItem dataItem = dataItems.get(0);
+ assertTrue(dataItem instanceof UnsignedInteger);
+ assertEquals(value, ((UnsignedInteger) dataItem).getValue());
+ }
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/encoder/AbstractEncoderTest.java b/src/test/java/co/nstant/in/cbor/encoder/AbstractEncoderTest.java
new file mode 100644
index 0000000..7d73883
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/encoder/AbstractEncoderTest.java
@@ -0,0 +1,79 @@
+package co.nstant.in.cbor.encoder;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.MajorType;
+
+public class AbstractEncoderTest {
+
+ private class TestEncoder extends AbstractEncoder<Object> {
+
+ public TestEncoder(OutputStream outputStream) {
+ super(null, outputStream);
+ }
+
+ @Override
+ public void encode(Object dataItem) throws CborException {
+ }
+
+ public void doEncodeTypeAndLength(long length) throws CborException {
+ encodeTypeAndLength(MajorType.ARRAY, length);
+ }
+
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowCborExceptionOnUnderlyingIoException() throws CborException {
+ final int[] counter = new int[1];
+ new CborEncoder(new OutputStream() {
+
+ @Override
+ public synchronized void write(int b) throws IOException {
+ if (++counter[0] == 3) {
+ throw new IOException();
+ }
+ }
+
+ }).encode(new CborBuilder().startString().add("string").end().build());
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowCborExceptionOnUnderlyingIoException2() throws CborException {
+ new CborEncoder(new OutputStream() {
+
+ @Override
+ public synchronized void write(int b) throws IOException {
+ throw new IOException();
+ }
+
+ }).encode(new CborBuilder().startArray().add(1).end().build());
+ }
+
+ @Test
+ public void shallEncode32bit() throws CborException {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ TestEncoder encoder = new TestEncoder(outputStream);
+ encoder.doEncodeTypeAndLength(4294967296L);
+ byte[] bytes = outputStream.toByteArray();
+ assertEquals(9, bytes.length);
+ assertEquals((byte) 0x9B, bytes[0]);
+ assertEquals((byte) 0x00, bytes[1]);
+ assertEquals((byte) 0x00, bytes[2]);
+ assertEquals((byte) 0x00, bytes[3]);
+ assertEquals((byte) 0x01, bytes[4]);
+ assertEquals((byte) 0x00, bytes[5]);
+ assertEquals((byte) 0x00, bytes[6]);
+ assertEquals((byte) 0x00, bytes[7]);
+ assertEquals((byte) 0x00, bytes[8]);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/encoder/ByteStringEncoderTest.java b/src/test/java/co/nstant/in/cbor/encoder/ByteStringEncoderTest.java
new file mode 100644
index 0000000..97c13ee
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/encoder/ByteStringEncoderTest.java
@@ -0,0 +1,37 @@
+package co.nstant.in.cbor.encoder;
+
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.ByteString;
+import co.nstant.in.cbor.model.DataItem;
+
+public class ByteStringEncoderTest {
+
+ @Test
+ public void shouldEncodeNullString() throws CborException {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ List<DataItem> dataItems = new CborBuilder()
+ .add((ByteString) null)
+ .build();
+ new CborEncoder(byteArrayOutputStream).encode(dataItems);
+ }
+
+ @Test
+ public void shouldEncodeChunkedString() throws CborException {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ List<DataItem> dataItems = new CborBuilder()
+ .add(new ByteString(null))
+ .add(new ByteString("test".getBytes()))
+ .startByteString("test".getBytes())
+ .end()
+ .build();
+ new CborEncoder(byteArrayOutputStream).encode(dataItems);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/encoder/MapEncoderTest.java b/src/test/java/co/nstant/in/cbor/encoder/MapEncoderTest.java
new file mode 100644
index 0000000..fb11cfd
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/encoder/MapEncoderTest.java
@@ -0,0 +1,31 @@
+package co.nstant.in.cbor.encoder;
+
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+public class MapEncoderTest {
+
+ @Test
+ public void shouldEncodeMap() throws CborException {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ List<DataItem> dataItems = new CborBuilder()
+ .addMap()
+ .put(1, true)
+ .put(".", true)
+ .put(3, true)
+ .put("..", true)
+ .put(2, true)
+ .put("...", true)
+ .end()
+ .build();
+ new CborEncoder(byteArrayOutputStream).encode(dataItems);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/encoder/RationalNumberEncoderTest.java b/src/test/java/co/nstant/in/cbor/encoder/RationalNumberEncoderTest.java
new file mode 100644
index 0000000..bf3cde5
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/encoder/RationalNumberEncoderTest.java
@@ -0,0 +1,55 @@
+package co.nstant.in.cbor.encoder;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.Array;
+import co.nstant.in.cbor.model.RationalNumber;
+import co.nstant.in.cbor.model.Tag;
+import co.nstant.in.cbor.model.UnsignedInteger;
+
+public class RationalNumberEncoderTest {
+
+ private static final UnsignedInteger ONE = new UnsignedInteger(1);
+ private static final UnsignedInteger TWO = new UnsignedInteger(2);
+
+ private ByteArrayOutputStream outputStream;
+ private CborEncoder encoder;
+
+ @Before
+ public void setup() {
+ outputStream = new ByteArrayOutputStream();
+ encoder = new CborEncoder(outputStream);
+ }
+
+ @Test
+ public void shouldEncode() throws CborException {
+ encoder.encode(new RationalNumber(ONE, TWO));
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
+ CborDecoder decoder = new CborDecoder(inputStream);
+
+ Array expected = new Array();
+ expected.setTag(11);
+ expected.add(ONE);
+ expected.add(TWO);
+
+ Object object = decoder.decodeNext();
+ assertTrue(object instanceof Array);
+ Array decoded = (Array) object;
+
+ assertEquals(new Tag(30), decoded.getTag());
+ assertEquals(2, decoded.getDataItems().size());
+ assertEquals(ONE, decoded.getDataItems().get(0));
+ assertEquals(TWO, decoded.getDataItems().get(1));
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/encoder/SpecialEncoderTest.java b/src/test/java/co/nstant/in/cbor/encoder/SpecialEncoderTest.java
new file mode 100644
index 0000000..1789890
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/encoder/SpecialEncoderTest.java
@@ -0,0 +1,52 @@
+package co.nstant.in.cbor.encoder;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.Special;
+import co.nstant.in.cbor.model.SpecialType;
+
+public class SpecialEncoderTest {
+
+ private class Mock extends Special {
+
+ public Mock(SpecialType specialType) {
+ super(specialType);
+ }
+
+ }
+
+ private SpecialEncoder encoder;
+
+ @Before
+ public void setup() {
+ encoder = new SpecialEncoder(null, null);
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldNotEncodeReserved() throws CborException {
+ encoder.encode(new Mock(SpecialType.UNALLOCATED));
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldVerifyImplementation1() throws CborException {
+ encoder.encode(new Mock(SpecialType.IEEE_754_DOUBLE_PRECISION_FLOAT));
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldVerifyImplementation2() throws CborException {
+ encoder.encode(new Mock(SpecialType.IEEE_754_HALF_PRECISION_FLOAT));
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldVerifyImplementation3() throws CborException {
+ encoder.encode(new Mock(SpecialType.IEEE_754_SINGLE_PRECISION_FLOAT));
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldVerifyImplementation4() throws CborException {
+ encoder.encode(new Mock(SpecialType.SIMPLE_VALUE_NEXT_BYTE));
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/encoder/UnicodeStringEncoderTest.java b/src/test/java/co/nstant/in/cbor/encoder/UnicodeStringEncoderTest.java
new file mode 100644
index 0000000..d1e2dd0
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/encoder/UnicodeStringEncoderTest.java
@@ -0,0 +1,34 @@
+package co.nstant.in.cbor.encoder;
+
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+public class UnicodeStringEncoderTest {
+
+ @Test
+ public void shouldEncodeNullString() throws CborException {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ List<DataItem> dataItems = new CborBuilder()
+ .add((String) null)
+ .build();
+ new CborEncoder(byteArrayOutputStream).encode(dataItems);
+ }
+
+ @Test
+ public void shouldEncodeChunkedString() throws CborException {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ List<DataItem> dataItems = new CborBuilder()
+ .startString("test")
+ .end()
+ .build();
+ new CborEncoder(byteArrayOutputStream).encode(dataItems);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example01Test.java b/src/test/java/co/nstant/in/cbor/examples/Example01Test.java
new file mode 100644
index 0000000..82747ef
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example01Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractNumberTest;
+
+/**
+ * 0 -> 0x00
+ */
+public class Example01Test extends AbstractNumberTest {
+
+ public Example01Test() {
+ super(0, new byte[] { 0x00 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example02Test.java b/src/test/java/co/nstant/in/cbor/examples/Example02Test.java
new file mode 100644
index 0000000..4c0bd2f
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example02Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractNumberTest;
+
+/**
+ * 0 -> 0x00
+ */
+public class Example02Test extends AbstractNumberTest {
+
+ public Example02Test() {
+ super(1, new byte[] { 0x01 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example03Test.java b/src/test/java/co/nstant/in/cbor/examples/Example03Test.java
new file mode 100644
index 0000000..a5029e0
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example03Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractNumberTest;
+
+/**
+ * 10 -> 0x0a
+ */
+public class Example03Test extends AbstractNumberTest {
+
+ public Example03Test() {
+ super(10, new byte[] { 0x0a });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example04Test.java b/src/test/java/co/nstant/in/cbor/examples/Example04Test.java
new file mode 100644
index 0000000..bd46947
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example04Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractNumberTest;
+
+/**
+ * 23 -> 0x17
+ */
+public class Example04Test extends AbstractNumberTest {
+
+ public Example04Test() {
+ super(23, new byte[] { 0x17 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example05Test.java b/src/test/java/co/nstant/in/cbor/examples/Example05Test.java
new file mode 100644
index 0000000..e4b3fcf
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example05Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractNumberTest;
+
+/**
+ * 24 -> 0x1818
+ */
+public class Example05Test extends AbstractNumberTest {
+
+ public Example05Test() {
+ super(24, new byte[] { 0x18, 0x18 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example06Test.java b/src/test/java/co/nstant/in/cbor/examples/Example06Test.java
new file mode 100644
index 0000000..807082b
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example06Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractNumberTest;
+
+/**
+ * 25 -> 0x1819
+ */
+public class Example06Test extends AbstractNumberTest {
+
+ public Example06Test() {
+ super(25, new byte[] { 0x18, 0x19 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example07Test.java b/src/test/java/co/nstant/in/cbor/examples/Example07Test.java
new file mode 100644
index 0000000..418745c
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example07Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractNumberTest;
+
+/**
+ * 100 -> 0x1864
+ */
+public class Example07Test extends AbstractNumberTest {
+
+ public Example07Test() {
+ super(100, new byte[] { 0x18, 0x64 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example08Test.java b/src/test/java/co/nstant/in/cbor/examples/Example08Test.java
new file mode 100644
index 0000000..22a992d
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example08Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractNumberTest;
+
+/**
+ * 1000 -> 0x1903e8
+ */
+public class Example08Test extends AbstractNumberTest {
+
+ public Example08Test() {
+ super(1000, new byte[] { 0x19, 0x03, (byte) 0xe8 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example09Test.java b/src/test/java/co/nstant/in/cbor/examples/Example09Test.java
new file mode 100644
index 0000000..4b6cfef
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example09Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractNumberTest;
+
+/**
+ * 1000000 -> 0x1a000f4240
+ */
+public class Example09Test extends AbstractNumberTest {
+
+ public Example09Test() {
+ super(1000000, new byte[] { 0x1a, 0x00, 0x0f, 0x42, 0x40 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example10Test.java b/src/test/java/co/nstant/in/cbor/examples/Example10Test.java
new file mode 100644
index 0000000..1e11890
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example10Test.java
@@ -0,0 +1,15 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractNumberTest;
+
+/**
+ * 1000000000000 -> 0x1b 00 00 00 e8 d4 a5 10 00
+ */
+public class Example10Test extends AbstractNumberTest {
+
+ public Example10Test() {
+ super(1000000000000L, new byte[] { 0x1b, 0x00, 0x00, 0x00,
+ (byte) 0xe8, (byte) 0xd4, (byte) 0xa5, 0x10, 0x00 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example11Test.java b/src/test/java/co/nstant/in/cbor/examples/Example11Test.java
new file mode 100644
index 0000000..ec5240c
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example11Test.java
@@ -0,0 +1,19 @@
+package co.nstant.in.cbor.examples;
+
+import java.math.BigInteger;
+
+import co.nstant.in.cbor.model.AbstractNumberTest;
+
+/**
+ * 18446744073709551615 -> 0x1bffffffffffffffff
+ */
+public class Example11Test extends AbstractNumberTest {
+
+ public Example11Test() {
+ super(new BigInteger("18446744073709551615"),
+ new byte[] { 0x1b, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example12Test.java b/src/test/java/co/nstant/in/cbor/examples/Example12Test.java
new file mode 100644
index 0000000..1f86e85
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example12Test.java
@@ -0,0 +1,52 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.ByteString;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Tag;
+import co.nstant.in.cbor.model.UnsignedInteger;
+
+/**
+ * 18446744073709551616 -> 0xc249010000000000000000
+ */
+public class Example12Test {
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteArrayOutputStream);
+ encoder.encode(new UnsignedInteger(new BigInteger(
+ "18446744073709551616")));
+ Assert.assertArrayEquals(new byte[] { (byte) 0xc2, 0x49, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ byteArrayOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
+ new byte[] { (byte) 0xc2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 });
+ CborDecoder decoder = new CborDecoder(byteArrayInputStream);
+ DataItem b = decoder.decodeNext();
+
+ Assert.assertTrue(b.hasTag());
+ Tag tag = b.getTag();
+ Assert.assertEquals(2, tag.getValue());
+
+ Assert.assertTrue(b instanceof ByteString);
+ ByteString byteString = (ByteString) b;
+ Assert.assertArrayEquals(new byte[] { (byte) 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00 }, byteString.getBytes());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example13Test.java b/src/test/java/co/nstant/in/cbor/examples/Example13Test.java
new file mode 100644
index 0000000..6d172b9
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example13Test.java
@@ -0,0 +1,19 @@
+package co.nstant.in.cbor.examples;
+
+import java.math.BigInteger;
+
+import co.nstant.in.cbor.model.AbstractNumberTest;
+
+/**
+ * -18446744073709551616 -> 0x3bffffffffffffffff
+ */
+public class Example13Test extends AbstractNumberTest {
+
+ public Example13Test() {
+ super(new BigInteger("-18446744073709551616"),
+ new byte[] { (byte) 0x3b, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example14Test.java b/src/test/java/co/nstant/in/cbor/examples/Example14Test.java
new file mode 100644
index 0000000..8cca685
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example14Test.java
@@ -0,0 +1,52 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.ByteString;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.NegativeInteger;
+import co.nstant.in.cbor.model.Tag;
+
+/**
+ * -18446744073709551617 -> 0xc349010000000000000000
+ */
+public class Example14Test {
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteArrayOutputStream);
+ encoder.encode(new NegativeInteger(new BigInteger(
+ "-18446744073709551617")));
+ Assert.assertArrayEquals(new byte[] { (byte) 0xc3, 0x49, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ byteArrayOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
+ new byte[] { (byte) 0xc3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 });
+ CborDecoder decoder = new CborDecoder(byteArrayInputStream);
+ DataItem b = decoder.decodeNext();
+
+ Assert.assertTrue(b.hasTag());
+ Tag tag = b.getTag();
+ Assert.assertEquals(3, tag.getValue());
+
+ Assert.assertTrue(b instanceof ByteString);
+ ByteString byteString = (ByteString) b;
+ Assert.assertArrayEquals(new byte[] { (byte) 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00 }, byteString.getBytes());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example15Test.java b/src/test/java/co/nstant/in/cbor/examples/Example15Test.java
new file mode 100644
index 0000000..4a8ad1f
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example15Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractNumberTest;
+
+/**
+ * -1 -> 0x20
+ */
+public class Example15Test extends AbstractNumberTest {
+
+ public Example15Test() {
+ super(-1, new byte[] { 0x20 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example16Test.java b/src/test/java/co/nstant/in/cbor/examples/Example16Test.java
new file mode 100644
index 0000000..e3d63bc
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example16Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractNumberTest;
+
+/**
+ * -10 -> 0x29
+ */
+public class Example16Test extends AbstractNumberTest {
+
+ public Example16Test() {
+ super(-10, new byte[] { 0x29 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example17Test.java b/src/test/java/co/nstant/in/cbor/examples/Example17Test.java
new file mode 100644
index 0000000..f27607f
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example17Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractNumberTest;
+
+/**
+ * -100 -> 0x3863
+ */
+public class Example17Test extends AbstractNumberTest {
+
+ public Example17Test() {
+ super(-100, new byte[] { 0x38, 0x63 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example18Test.java b/src/test/java/co/nstant/in/cbor/examples/Example18Test.java
new file mode 100644
index 0000000..ff7cec0
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example18Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractNumberTest;
+
+/**
+ * -1000 -> 0x3903e7
+ */
+public class Example18Test extends AbstractNumberTest {
+
+ public Example18Test() {
+ super(-1000, new byte[] { 0x39, 0x03, (byte) 0xe7 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example19Test.java b/src/test/java/co/nstant/in/cbor/examples/Example19Test.java
new file mode 100644
index 0000000..d47b10a
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example19Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractHalfPrecisionFloatTest;
+
+/**
+ * 0.0 -> 0xf90000
+ */
+public class Example19Test extends AbstractHalfPrecisionFloatTest {
+
+ public Example19Test() {
+ super(0.0f, new byte[] { (byte) 0xf9, 0x00, 0x00 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example20Test.java b/src/test/java/co/nstant/in/cbor/examples/Example20Test.java
new file mode 100644
index 0000000..b20c298
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example20Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractHalfPrecisionFloatTest;
+
+/**
+ * Example 20: -0.0 -> 0xf98000
+ */
+public class Example20Test extends AbstractHalfPrecisionFloatTest {
+
+ public Example20Test() {
+ super(-0.0f, new byte[] { (byte) 0xf9, (byte) 0x80, 0x00 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example21Test.java b/src/test/java/co/nstant/in/cbor/examples/Example21Test.java
new file mode 100644
index 0000000..9d29b66
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example21Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractHalfPrecisionFloatTest;
+
+/**
+ * Example 21: 1.0 -> 0xf93c00
+ */
+public class Example21Test extends AbstractHalfPrecisionFloatTest {
+
+ public Example21Test() {
+ super(1.0f, new byte[] { (byte) 0xf9, 0x3c, 0x00 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example22Test.java b/src/test/java/co/nstant/in/cbor/examples/Example22Test.java
new file mode 100644
index 0000000..e79df39
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example22Test.java
@@ -0,0 +1,16 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractDoublePrecisionFloatTest;
+
+/**
+ * Example 22: 1.1 -> 0xfb 3f f1 99 99 99 99 99 9a
+ */
+public class Example22Test extends AbstractDoublePrecisionFloatTest {
+
+ public Example22Test() {
+ super(1.1d, new byte[] { (byte) 0xfb, 0x3f, (byte) 0xf1, (byte) 0x99,
+ (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99,
+ (byte) 0x9a });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example23Test.java b/src/test/java/co/nstant/in/cbor/examples/Example23Test.java
new file mode 100644
index 0000000..e970b83
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example23Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractHalfPrecisionFloatTest;
+
+/**
+ * 1.5 -> 0xf93e00
+ */
+public class Example23Test extends AbstractHalfPrecisionFloatTest {
+
+ public Example23Test() {
+ super(1.5f, new byte[] { (byte) 0xf9, 0x3e, 0x00 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example24Test.java b/src/test/java/co/nstant/in/cbor/examples/Example24Test.java
new file mode 100644
index 0000000..b798523
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example24Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractHalfPrecisionFloatTest;
+
+/**
+ * 65504.0 -> 0xf97bff
+ */
+public class Example24Test extends AbstractHalfPrecisionFloatTest {
+
+ public Example24Test() {
+ super(65504.0f, new byte[] { (byte) 0xf9, 0x7b, (byte) 0xff });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example25Test.java b/src/test/java/co/nstant/in/cbor/examples/Example25Test.java
new file mode 100644
index 0000000..f8ca008
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example25Test.java
@@ -0,0 +1,15 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractSinglePrecisionFloatTest;
+
+/**
+ * 100000.0 -> 0xfa47c35000
+ */
+public class Example25Test extends AbstractSinglePrecisionFloatTest {
+
+ public Example25Test() {
+ super(100000.0f, new byte[] { (byte) 0xfa, 0x47, (byte) 0xc3, 0x50,
+ 0x00 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example26Test.java b/src/test/java/co/nstant/in/cbor/examples/Example26Test.java
new file mode 100644
index 0000000..d3e5125
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example26Test.java
@@ -0,0 +1,16 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractSinglePrecisionFloatTest;
+
+/**
+ * 3.4028234663852886e+38 -> 0xfa 7f 7f ff ff
+ */
+public class Example26Test extends AbstractSinglePrecisionFloatTest {
+
+ public Example26Test() {
+ super(Float.parseFloat("3.4028234663852886e+38"), new byte[] {
+ (byte) 0xfa, 0x7f, (byte) 0x7f, (byte) 0xff,
+ (byte) 0xff });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example27Test.java b/src/test/java/co/nstant/in/cbor/examples/Example27Test.java
new file mode 100644
index 0000000..79f722a
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example27Test.java
@@ -0,0 +1,16 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractDoublePrecisionFloatTest;
+
+/**
+ * 1.0e+300 -> 0xfb 7e 37 e4 3c 88 00 75 9c
+ */
+public class Example27Test extends AbstractDoublePrecisionFloatTest {
+
+ public Example27Test() {
+ super(Double.parseDouble("1.0e+300"), new byte[] {
+ (byte) 0xfb, 0x7e, 0x37, (byte) 0xe4, 0x3c,
+ (byte) 0x88, 0x00, 0x75, (byte) 0x9c });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example28Test.java b/src/test/java/co/nstant/in/cbor/examples/Example28Test.java
new file mode 100644
index 0000000..b15ebbc
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example28Test.java
@@ -0,0 +1,15 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractHalfPrecisionFloatTest;
+
+/**
+ * 5.960464477539063e-08 -> 0xf90001
+ */
+public class Example28Test extends AbstractHalfPrecisionFloatTest {
+
+ public Example28Test() {
+ super(Float.parseFloat("5.960464477539063e-08"), new byte[] {
+ (byte) 0xf9, 0x00, 0x01 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example29Test.java b/src/test/java/co/nstant/in/cbor/examples/Example29Test.java
new file mode 100644
index 0000000..2def77e
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example29Test.java
@@ -0,0 +1,15 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractHalfPrecisionFloatTest;
+
+/**
+ * 6.103515625e-05 -> 0xf90400
+ */
+public class Example29Test extends AbstractHalfPrecisionFloatTest {
+
+ public Example29Test() {
+ super(Float.parseFloat("6.103515625e-05"), new byte[] {
+ (byte) 0xf9, 0x04, 0x00 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example30Test.java b/src/test/java/co/nstant/in/cbor/examples/Example30Test.java
new file mode 100644
index 0000000..8f8db91
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example30Test.java
@@ -0,0 +1,15 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractHalfPrecisionFloatTest;
+
+/**
+ * -4,0 -> 0xf9c400
+ */
+public class Example30Test extends AbstractHalfPrecisionFloatTest {
+
+ public Example30Test() {
+ super(Float.parseFloat("-4.0"), new byte[] {
+ (byte) 0xf9, (byte) 0xc4, 0x00 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example31Test.java b/src/test/java/co/nstant/in/cbor/examples/Example31Test.java
new file mode 100644
index 0000000..e2d4391
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example31Test.java
@@ -0,0 +1,16 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractDoublePrecisionFloatTest;
+
+/**
+ * -4.1 -> 0xfb c0 10 66 66 66 66 66 66
+ */
+public class Example31Test extends AbstractDoublePrecisionFloatTest {
+
+ public Example31Test() {
+ super(Double.parseDouble("-4.1"), new byte[] {
+ (byte) 0xfb, (byte) 0xc0, 0x10, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example32Test.java b/src/test/java/co/nstant/in/cbor/examples/Example32Test.java
new file mode 100644
index 0000000..d5315e6
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example32Test.java
@@ -0,0 +1,15 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractHalfPrecisionFloatTest;
+
+/**
+ * Infinity -> 0xf97c00
+ */
+public class Example32Test extends AbstractHalfPrecisionFloatTest {
+
+ public Example32Test() {
+ super(Float.POSITIVE_INFINITY, new byte[] {
+ (byte) 0xf9, 0x7c, 0x00 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example33Test.java b/src/test/java/co/nstant/in/cbor/examples/Example33Test.java
new file mode 100644
index 0000000..5118f62
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example33Test.java
@@ -0,0 +1,15 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractHalfPrecisionFloatTest;
+
+/**
+ * NaN -> 0xf97e00
+ */
+public class Example33Test extends AbstractHalfPrecisionFloatTest {
+
+ public Example33Test() {
+ super(Float.NaN, new byte[] {
+ (byte) 0xf9, 0x7e, 0x00 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example34Test.java b/src/test/java/co/nstant/in/cbor/examples/Example34Test.java
new file mode 100644
index 0000000..38c4583
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example34Test.java
@@ -0,0 +1,15 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractHalfPrecisionFloatTest;
+
+/**
+ * -Infinity -> 0xf9fc00
+ */
+public class Example34Test extends AbstractHalfPrecisionFloatTest {
+
+ public Example34Test() {
+ super(Float.NEGATIVE_INFINITY, new byte[] {
+ (byte) 0xf9, (byte) 0xfc, 0x00 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example35Test.java b/src/test/java/co/nstant/in/cbor/examples/Example35Test.java
new file mode 100644
index 0000000..a709a6b
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example35Test.java
@@ -0,0 +1,15 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractSinglePrecisionFloatTest;
+
+/**
+ * Infinity -> 0xfa 7f 80 00 00
+ */
+public class Example35Test extends AbstractSinglePrecisionFloatTest {
+
+ public Example35Test() {
+ super(Float.POSITIVE_INFINITY, new byte[] {
+ (byte) 0xfa, 0x7f, (byte) 0x80, 0x00, 0x00 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example36Test.java b/src/test/java/co/nstant/in/cbor/examples/Example36Test.java
new file mode 100644
index 0000000..1e056fe
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example36Test.java
@@ -0,0 +1,15 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractSinglePrecisionFloatTest;
+
+/**
+ * NaN -> 0xfa7fc00000
+ */
+public class Example36Test extends AbstractSinglePrecisionFloatTest {
+
+ public Example36Test() {
+ super(Float.NaN, new byte[] {
+ (byte) 0xfa, 0x7f, (byte) 0xc0, 0x00, 0x00 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example37Test.java b/src/test/java/co/nstant/in/cbor/examples/Example37Test.java
new file mode 100644
index 0000000..b5d0a47
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example37Test.java
@@ -0,0 +1,15 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractSinglePrecisionFloatTest;
+
+/**
+ * -Infinity -> 0xfa ff 80 00 00
+ */
+public class Example37Test extends AbstractSinglePrecisionFloatTest {
+
+ public Example37Test() {
+ super(Float.NEGATIVE_INFINITY, new byte[] {
+ (byte) 0xfa, (byte) 0xff, (byte) 0x80, 0x00, 0x00 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example38Test.java b/src/test/java/co/nstant/in/cbor/examples/Example38Test.java
new file mode 100644
index 0000000..671b7d7
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example38Test.java
@@ -0,0 +1,16 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractDoublePrecisionFloatTest;
+
+/**
+ * Infinity -> 0xfb 7f f0 00 00 00 00 00 00
+ */
+public class Example38Test extends AbstractDoublePrecisionFloatTest {
+
+ public Example38Test() {
+ super(Double.POSITIVE_INFINITY, new byte[] {
+ (byte) 0xfb, 0x7f, (byte) 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example39Test.java b/src/test/java/co/nstant/in/cbor/examples/Example39Test.java
new file mode 100644
index 0000000..501a231
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example39Test.java
@@ -0,0 +1,16 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractDoublePrecisionFloatTest;
+
+/**
+ * NaN -> 0xfb 7f f8 00 00 00 00 00 00
+ */
+public class Example39Test extends AbstractDoublePrecisionFloatTest {
+
+ public Example39Test() {
+ super(Double.NaN, new byte[] {
+ (byte) 0xfb, 0x7f, (byte) 0xf8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example40Test.java b/src/test/java/co/nstant/in/cbor/examples/Example40Test.java
new file mode 100644
index 0000000..cb633ea
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example40Test.java
@@ -0,0 +1,16 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractDoublePrecisionFloatTest;
+
+/**
+ * -Infinity -> 0xfb ff f0 00 00 00 00 00 00
+ */
+public class Example40Test extends AbstractDoublePrecisionFloatTest {
+
+ public Example40Test() {
+ super(Double.NEGATIVE_INFINITY, new byte[] {
+ (byte) 0xfb, (byte) 0xff, (byte) 0xf0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example41Test.java b/src/test/java/co/nstant/in/cbor/examples/Example41Test.java
new file mode 100644
index 0000000..f74daaa
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example41Test.java
@@ -0,0 +1,41 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.SimpleValue;
+
+/**
+ * false -> 0xf4
+ */
+public class Example41Test {
+
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0xf4 };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(SimpleValue.FALSE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ DataItem dataItem = decoder.decodeNext();
+ Assert.assertTrue(dataItem instanceof SimpleValue);
+ SimpleValue simpleValue = (SimpleValue) dataItem;
+ Assert.assertEquals(SimpleValue.FALSE, simpleValue);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example42Test.java b/src/test/java/co/nstant/in/cbor/examples/Example42Test.java
new file mode 100644
index 0000000..4f2d99f
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example42Test.java
@@ -0,0 +1,41 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.SimpleValue;
+
+/**
+ * true -> 0xf5
+ */
+public class Example42Test {
+
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0xf5 };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(SimpleValue.TRUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ DataItem dataItem = decoder.decodeNext();
+ Assert.assertTrue(dataItem instanceof SimpleValue);
+ SimpleValue simpleValue = (SimpleValue) dataItem;
+ Assert.assertEquals(SimpleValue.TRUE, simpleValue);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example43Test.java b/src/test/java/co/nstant/in/cbor/examples/Example43Test.java
new file mode 100644
index 0000000..e59e5c3
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example43Test.java
@@ -0,0 +1,41 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.SimpleValue;
+
+/**
+ * nil -> 0xf6
+ */
+public class Example43Test {
+
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0xf6 };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(SimpleValue.NULL);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ DataItem dataItem = decoder.decodeNext();
+ Assert.assertTrue(dataItem instanceof SimpleValue);
+ SimpleValue simpleValue = (SimpleValue) dataItem;
+ Assert.assertEquals(SimpleValue.NULL, simpleValue);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example44Test.java b/src/test/java/co/nstant/in/cbor/examples/Example44Test.java
new file mode 100644
index 0000000..f5a23ab
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example44Test.java
@@ -0,0 +1,41 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.SimpleValue;
+
+/**
+ * undefined -> 0xf7
+ */
+public class Example44Test {
+
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0xf7 };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(SimpleValue.UNDEFINED);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ DataItem dataItem = decoder.decodeNext();
+ Assert.assertTrue(dataItem instanceof SimpleValue);
+ SimpleValue simpleValue = (SimpleValue) dataItem;
+ Assert.assertEquals(SimpleValue.UNDEFINED, simpleValue);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example45Test.java b/src/test/java/co/nstant/in/cbor/examples/Example45Test.java
new file mode 100644
index 0000000..be5d75b
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example45Test.java
@@ -0,0 +1,42 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.SimpleValue;
+
+/**
+ * simple(16) -> 0xf0
+ */
+public class Example45Test {
+
+ private static final SimpleValue VALUE = new SimpleValue(16);
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0xf0 };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ DataItem dataItem = decoder.decodeNext();
+ Assert.assertTrue(dataItem instanceof SimpleValue);
+ SimpleValue simpleValue = (SimpleValue) dataItem;
+ Assert.assertEquals(VALUE, simpleValue);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example46Test.java b/src/test/java/co/nstant/in/cbor/examples/Example46Test.java
new file mode 100644
index 0000000..146c3f2
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example46Test.java
@@ -0,0 +1,42 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.SimpleValue;
+
+/**
+ * simple(24) -> 0xf818
+ */
+public class Example46Test {
+
+ private static final SimpleValue VALUE = new SimpleValue(24);
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0xf8, 0x18 };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ DataItem dataItem = decoder.decodeNext();
+ Assert.assertTrue(dataItem instanceof SimpleValue);
+ SimpleValue simpleValue = (SimpleValue) dataItem;
+ Assert.assertEquals(VALUE, simpleValue);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example47Test.java b/src/test/java/co/nstant/in/cbor/examples/Example47Test.java
new file mode 100644
index 0000000..2c3ca8d
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example47Test.java
@@ -0,0 +1,43 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.SimpleValue;
+
+/**
+ * simple(255) -> 0xf8ff
+ */
+public class Example47Test {
+
+ private static final SimpleValue VALUE = new SimpleValue(255);
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0xf8,
+ (byte) 0xff };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ DataItem dataItem = decoder.decodeNext();
+ Assert.assertTrue(dataItem instanceof SimpleValue);
+ SimpleValue simpleValue = (SimpleValue) dataItem;
+ Assert.assertEquals(VALUE, simpleValue);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example48Test.java b/src/test/java/co/nstant/in/cbor/examples/Example48Test.java
new file mode 100644
index 0000000..878bfaf
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example48Test.java
@@ -0,0 +1,52 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.UnicodeString;
+
+/**
+ * 0("2013-03-21T20:04:00Z") -> 0xc074323031332d30332d32315432303a30343a30305a
+ */
+public class Example48Test {
+
+ private final List<DataItem> VALUE;
+
+ private final byte[] ENCODED_VALUE = new byte[] { (byte) 0xc0, 0x74,
+ 0x32, 0x30, 0x31, 0x33, 0x2d, 0x30, 0x33, 0x2d, 0x32, 0x31, 0x54,
+ 0x32, 0x30, 0x3a, 0x30, 0x34, 0x3a, 0x30, 0x30, 0x5a };
+
+ public Example48Test() {
+ DataItem di = new UnicodeString("2013-03-21T20:04:00Z");
+ di.setTag(0);
+
+ VALUE = new CborBuilder().add(di).build();
+ }
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example49Test.java b/src/test/java/co/nstant/in/cbor/examples/Example49Test.java
new file mode 100644
index 0000000..1978935
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example49Test.java
@@ -0,0 +1,51 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.UnsignedInteger;
+
+/**
+ * 1(1363896240) -> 0xc11a514b67b0
+ */
+public class Example49Test {
+
+ private final List<DataItem> VALUE;
+
+ private final byte[] ENCODED_VALUE = new byte[] { (byte) 0xc1, 0x1a,
+ 0x51, 0x4b, 0x67, (byte) 0xb0 };
+
+ public Example49Test() {
+ DataItem di = new UnsignedInteger(1363896240);
+ di.setTag(1);
+
+ VALUE = new CborBuilder().add(di).build();
+ }
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example50Test.java b/src/test/java/co/nstant/in/cbor/examples/Example50Test.java
new file mode 100644
index 0000000..daa67b3
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example50Test.java
@@ -0,0 +1,52 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.DoublePrecisionFloat;
+
+/**
+ * 1(1363896240.5) -> 0xc1fb41d452d9ec200000
+ */
+public class Example50Test {
+
+ private final List<DataItem> VALUE;
+
+ private final byte[] ENCODED_VALUE = new byte[] { (byte) 0xc1,
+ (byte) 0xfb, 0x41, (byte) 0xd4, 0x52, (byte) 0xd9, (byte) 0xec,
+ 0x20, 0x00, 0x00 };
+
+ public Example50Test() {
+ DataItem di = new DoublePrecisionFloat(1363896240.5);
+ di.setTag(1);
+
+ VALUE = new CborBuilder().add(di).build();
+ }
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example51Test.java b/src/test/java/co/nstant/in/cbor/examples/Example51Test.java
new file mode 100644
index 0000000..7784881
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example51Test.java
@@ -0,0 +1,52 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.ByteString;
+import co.nstant.in.cbor.model.DataItem;
+
+/**
+ * 23(h'01020304') -> 0xd74401020304
+ */
+public class Example51Test {
+
+ private final List<DataItem> VALUE;
+
+ private final byte[] ENCODED_VALUE = new byte[] { (byte) 0xd7, 0x44,
+ 0x01, 0x02, 0x03, 0x04 };
+
+ public Example51Test() {
+ DataItem di = new ByteString(new byte[] { 0x01, 0x02, 0x03, 0x04 });
+ di.setTag(23);
+
+ VALUE = new CborBuilder().add(di).build();
+ }
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example52Test.java b/src/test/java/co/nstant/in/cbor/examples/Example52Test.java
new file mode 100644
index 0000000..cd78367
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example52Test.java
@@ -0,0 +1,51 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.ByteString;
+import co.nstant.in.cbor.model.DataItem;
+
+/**
+ * 24(h'6449455446') -> 0xd818456449455446
+ */
+public class Example52Test {
+
+ private final List<DataItem> VALUE;
+
+ private final byte[] ENCODED_VALUE = new byte[] { (byte) 0xd8, 0x18,
+ 0x45, 0x64, 0x49, 0x45, 0x54, 0x46 };
+
+ public Example52Test() {
+ DataItem di = new ByteString(new byte[] { 0x64, 0x49, 0x45, 0x54, 0x46 });
+ di.setTag(24);
+
+ VALUE = new CborBuilder().add(di).build();
+ }
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example53Test.java b/src/test/java/co/nstant/in/cbor/examples/Example53Test.java
new file mode 100644
index 0000000..dd0de16
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example53Test.java
@@ -0,0 +1,54 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.UnicodeString;
+
+/**
+ * 32("http://www.example.com") ->
+ * 0xd82076687474703a2f2f7777772e6578616d706c652e636f6d
+ */
+public class Example53Test {
+
+ private final List<DataItem> VALUE;
+
+ private final byte[] ENCODED_VALUE = new byte[] { (byte) 0xd8, 0x20,
+ 0x76, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
+ 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
+ 0x6d };
+
+ public Example53Test() {
+ DataItem di = new UnicodeString("http://www.example.com");
+ di.setTag(32);
+
+ VALUE = new CborBuilder().add(di).build();
+ }
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example54Test.java b/src/test/java/co/nstant/in/cbor/examples/Example54Test.java
new file mode 100644
index 0000000..026a699
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example54Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractByteStringTest;
+
+/**
+ * h'' -> 0x40
+ */
+public class Example54Test extends AbstractByteStringTest {
+
+ public Example54Test() {
+ super(new byte[] {}, new byte[] { 0x40 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example55Test.java b/src/test/java/co/nstant/in/cbor/examples/Example55Test.java
new file mode 100644
index 0000000..5191dbc
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example55Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractByteStringTest;
+
+/**
+ * h'01020304' -> 0x4401020304
+ */
+public class Example55Test extends AbstractByteStringTest {
+
+ public Example55Test() {
+ super(new byte[] { 0x01, 0x02, 0x03, 0x04 },
+ new byte[] { 0x44, 0x01, 0x02, 0x03, 0x04 });
+ }
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example56Test.java b/src/test/java/co/nstant/in/cbor/examples/Example56Test.java
new file mode 100644
index 0000000..49680c6
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example56Test.java
@@ -0,0 +1,15 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractStringTest;
+
+
+/**
+ * "" -> 0x60
+ */
+public class Example56Test extends AbstractStringTest {
+
+ public Example56Test() {
+ super("", new byte[] { 0x60 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example57Test.java b/src/test/java/co/nstant/in/cbor/examples/Example57Test.java
new file mode 100644
index 0000000..eb1f866
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example57Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractStringTest;
+
+/**
+ * "a" -> 0x6161
+ */
+public class Example57Test extends AbstractStringTest {
+
+ public Example57Test() {
+ super("a", new byte[] { 0x61, 0x61 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example58Test.java b/src/test/java/co/nstant/in/cbor/examples/Example58Test.java
new file mode 100644
index 0000000..53b3555
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example58Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractStringTest;
+
+/**
+ * "IETF" -> 0x64 49 45 54 46
+ */
+public class Example58Test extends AbstractStringTest {
+
+ public Example58Test() {
+ super("IETF", new byte[] { 0x64, 0x49, 0x45, 0x54, 0x46 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example59Test.java b/src/test/java/co/nstant/in/cbor/examples/Example59Test.java
new file mode 100644
index 0000000..c2afbac
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example59Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractStringTest;
+
+/**
+ * "\"\\" -> 0x62225c
+ */
+public class Example59Test extends AbstractStringTest {
+
+ public Example59Test() {
+ super("\"\\", new byte[] { 0x62, 0x22, 0x5c });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example60Test.java b/src/test/java/co/nstant/in/cbor/examples/Example60Test.java
new file mode 100644
index 0000000..89f1fd4
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example60Test.java
@@ -0,0 +1,14 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractStringTest;
+
+/**
+ * "\u00fc" -> 0x62c3bc
+ */
+public class Example60Test extends AbstractStringTest {
+
+ public Example60Test() {
+ super("\u00fc", new byte[] { 0x62, (byte) 0xc3, (byte) 0xbc });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example61Test.java b/src/test/java/co/nstant/in/cbor/examples/Example61Test.java
new file mode 100644
index 0000000..4b6cc91
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example61Test.java
@@ -0,0 +1,15 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractStringTest;
+
+/**
+ * "\u6c34" -> 0x63e6b0b4
+ */
+public class Example61Test extends AbstractStringTest {
+
+ public Example61Test() {
+ super("\u6c34", new byte[] { 0x63, (byte) 0xe6, (byte) 0xb0,
+ (byte) 0xb4 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example62Test.java b/src/test/java/co/nstant/in/cbor/examples/Example62Test.java
new file mode 100644
index 0000000..8711b0c
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example62Test.java
@@ -0,0 +1,15 @@
+package co.nstant.in.cbor.examples;
+
+import co.nstant.in.cbor.model.AbstractStringTest;
+
+/**
+ * "\ud800\udd51" -> 0x64f0908591
+ */
+public class Example62Test extends AbstractStringTest {
+
+ public Example62Test() {
+ super("\ud800\udd51", new byte[] { 0x64, (byte) 0xf0, (byte) 0x90,
+ (byte) 0x85, (byte) 0x91 });
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example63Test.java b/src/test/java/co/nstant/in/cbor/examples/Example63Test.java
new file mode 100644
index 0000000..24b9330
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example63Test.java
@@ -0,0 +1,42 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.Array;
+import co.nstant.in.cbor.model.DataItem;
+
+/**
+ * [] -> 0x80
+ */
+public class Example63Test {
+
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0x80 };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(new CborBuilder().addArray().end().build());
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ DataItem dataItem = decoder.decodeNext();
+ Assert.assertTrue(dataItem instanceof Array);
+ Array array = (Array) dataItem;
+ Assert.assertTrue(array.getDataItems().isEmpty());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example64Test.java b/src/test/java/co/nstant/in/cbor/examples/Example64Test.java
new file mode 100644
index 0000000..8ddffb0
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example64Test.java
@@ -0,0 +1,51 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.Array;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Number;
+
+/**
+ * [1, 2, 3] -> 0x83010203
+ */
+public class Example64Test {
+
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0x83, 0x01,
+ 0x02, 0x03 };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(new CborBuilder().addArray().add(1).add(2).add(3).end()
+ .build());
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ DataItem dataItem = decoder.decodeNext();
+ Assert.assertTrue(dataItem instanceof Array);
+ Array array = (Array) dataItem;
+ Assert.assertEquals(3, array.getDataItems().size());
+ Assert.assertEquals(1, ((Number) array.getDataItems().get(0))
+ .getValue().intValue());
+ Assert.assertEquals(2, ((Number) array.getDataItems().get(1))
+ .getValue().intValue());
+ Assert.assertEquals(3, ((Number) array.getDataItems().get(2))
+ .getValue().intValue());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example65Test.java b/src/test/java/co/nstant/in/cbor/examples/Example65Test.java
new file mode 100644
index 0000000..6c6aff6
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example65Test.java
@@ -0,0 +1,89 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.Array;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Number;
+
+/**
+ * [1, [2, 3], [4, 5]] -> 0x83 01 82 02 03 82 04 05
+ */
+public class Example65Test {
+
+ private static final List<DataItem> VALUE = new CborBuilder().addArray()
+ .add(1).addArray().add(2).add(3).end().addArray().add(4).add(5)
+ .end().end().build();
+
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0x83, 0x01,
+ (byte) 0x82, 0x02, 0x03, (byte) 0x82, 0x04, 0x05 };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ DataItem dataItem = decoder.decodeNext();
+ Assert.assertTrue(dataItem instanceof Array);
+ Array array = (Array) dataItem;
+ Assert.assertEquals(3, array.getDataItems().size());
+
+ DataItem dataItem1 = array.getDataItems().get(0);
+ DataItem dataItem2 = array.getDataItems().get(1);
+ DataItem dataItem3 = array.getDataItems().get(2);
+
+ Assert.assertTrue(dataItem1 instanceof Number);
+ Assert.assertTrue(dataItem2 instanceof Array);
+ Assert.assertTrue(dataItem3 instanceof Array);
+
+ Number number = (Number) dataItem1;
+ Array array1 = (Array) dataItem2;
+ Array array2 = (Array) dataItem3;
+
+ Assert.assertEquals(1, number.getValue().intValue());
+ Assert.assertEquals(2, array1.getDataItems().size());
+ Assert.assertEquals(2, array2.getDataItems().size());
+
+ DataItem array1item1 = array1.getDataItems().get(0);
+ DataItem array1item2 = array1.getDataItems().get(1);
+
+ Assert.assertTrue(array1item1 instanceof Number);
+ Assert.assertTrue(array1item2 instanceof Number);
+
+ Number array1number1 = (Number) array1item1;
+ Number array1number2 = (Number) array1item2;
+
+ Assert.assertEquals(2, array1number1.getValue().intValue());
+ Assert.assertEquals(3, array1number2.getValue().intValue());
+
+ DataItem array2item1 = array2.getDataItems().get(0);
+ DataItem array2item2 = array2.getDataItems().get(1);
+
+ Assert.assertTrue(array2item1 instanceof Number);
+ Assert.assertTrue(array2item2 instanceof Number);
+
+ Number array2number1 = (Number) array2item1;
+ Number array2number2 = (Number) array2item2;
+
+ Assert.assertEquals(4, array2number1.getValue().intValue());
+ Assert.assertEquals(5, array2number2.getValue().intValue());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example66Test.java b/src/test/java/co/nstant/in/cbor/examples/Example66Test.java
new file mode 100644
index 0000000..32f9a6d
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example66Test.java
@@ -0,0 +1,55 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+/**
+ * [1, 2, 3, 4, 5, 6,7, 8, 9, 10, 11, 12,13, 14, 15, 16, 17,18, 19, 20, 21, 22,
+ * 23, 24, 25] -> 0x98 190102030405060708090a0b0c0d0e0f101112131415161718181819
+ */
+public class Example66Test {
+
+ private static final List<DataItem> VALUE = new CborBuilder()
+ .addArray()
+ .add(1).add(2).add(3).add(4).add(5)
+ .add(6).add(7).add(8).add(9).add(10)
+ .add(11).add(12).add(13).add(14).add(15)
+ .add(16).add(17).add(18).add(19).add(20)
+ .add(21).add(22).add(23).add(24).add(25)
+ .end()
+ .build();
+
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0x98,
+ 0x19, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+ 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+ 0x14, 0x15, 0x16, 0x17, 0x18, 0x18, 0x18, 0x19
+ };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example67Test.java b/src/test/java/co/nstant/in/cbor/examples/Example67Test.java
new file mode 100644
index 0000000..c4091bf
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example67Test.java
@@ -0,0 +1,43 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+/**
+ * {} -> 0xa0
+ */
+public class Example67Test {
+
+ private static final List<DataItem> VALUE = new CborBuilder()
+ .addMap().end().build();
+
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0xa0 };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example68Test.java b/src/test/java/co/nstant/in/cbor/examples/Example68Test.java
new file mode 100644
index 0000000..0bca2c4
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example68Test.java
@@ -0,0 +1,44 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+/**
+ * {1: 2, 3: 4} -> 0xa201020304
+ */
+public class Example68Test {
+
+ private static final List<DataItem> VALUE = new CborBuilder()
+ .addMap().put(1, 2).put(3, 4).end().build();
+
+ private static final byte[] ENCODED_VALUE = new byte[] {
+ (byte) 0xa2, 0x01, 0x02, 0x03, 0x04 };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example69Test.java b/src/test/java/co/nstant/in/cbor/examples/Example69Test.java
new file mode 100644
index 0000000..ba78f42
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example69Test.java
@@ -0,0 +1,46 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+/**
+ * {"a": 1, "b": [2,3]} -> 0xa26161016162820203
+ */
+public class Example69Test {
+
+ private static final List<DataItem> VALUE = new CborBuilder()
+ .addMap().put("a", 1).putArray("b").add(2).add(3).end()
+ .end().build();
+
+ private static final byte[] ENCODED_VALUE = new byte[] {
+ (byte) 0xa2, 0x61, 0x61, 0x01, 0x61, 0x62, (byte) 0x82,
+ 0x02, 0x03 };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example70Test.java b/src/test/java/co/nstant/in/cbor/examples/Example70Test.java
new file mode 100644
index 0000000..6703ffe
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example70Test.java
@@ -0,0 +1,50 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+/**
+ * ["a", {"b": "c"}] -> 0x826161a161626163
+ */
+public class Example70Test {
+
+ private static final List<DataItem> VALUE = new CborBuilder()
+ .addArray()
+ .add("a")
+ .addMap()
+ .put("b", "c")
+ .end()
+ .end()
+ .build();
+
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0x82, 0x61,
+ 0x61, (byte) 0xa1, 0x61, 0x62, 0x61, 0x63 };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example71Test.java b/src/test/java/co/nstant/in/cbor/examples/Example71Test.java
new file mode 100644
index 0000000..11d5edf
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example71Test.java
@@ -0,0 +1,54 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+/**
+ * {"a": "A", "b": "B", "c": "C", "d": "D","e": "E"} ->
+ * 0xa56161614161626142616361436164614461656145
+ */
+public class Example71Test {
+
+ private static final List<DataItem> VALUE = new CborBuilder()
+ .addMap()
+ .put("a", "A")
+ .put("b", "B")
+ .put("c", "C")
+ .put("d", "D")
+ .put("e", "E")
+ .end()
+ .build();
+
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0xa5, 0x61,
+ 0x61, 0x61, 0x41, 0x61, 0x62, 0x61, 0x42, 0x61, 0x63, 0x61,
+ 0x43, 0x61, 0x64, 0x61, 0x44, 0x61, 0x65, 0x61, 0x45
+ };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example72Test.java b/src/test/java/co/nstant/in/cbor/examples/Example72Test.java
new file mode 100644
index 0000000..374b317
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example72Test.java
@@ -0,0 +1,50 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+/**
+ * (_ h'0102', h'030405') -> 0x5f42010243030405ff
+ */
+public class Example72Test {
+
+ private static final List<DataItem> VALUE = new CborBuilder()
+ .startByteString()
+ .add(new byte[] { 0x01, 0x02 })
+ .add(new byte[] { 0x03, 0x04, 0x05 })
+ .end()
+ .build();
+
+ private static final byte[] ENCODED_VALUE = new byte[] {
+ 0x5f, 0x42, 0x01, 0x02, 0x43, 0x03, 0x04, 0x05, (byte) 0xff
+ };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ decoder.setAutoDecodeInfinitiveByteStrings(false);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example73Test.java b/src/test/java/co/nstant/in/cbor/examples/Example73Test.java
new file mode 100644
index 0000000..ebb12dc
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example73Test.java
@@ -0,0 +1,51 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+/**
+ * (_ "strea", "ming") -> 0x7f657374726561646d696e67ff
+ */
+public class Example73Test {
+
+ private static final List<DataItem> VALUE = new CborBuilder()
+ .startString()
+ .add("strea")
+ .add("ming")
+ .end()
+ .build();
+
+ private static final byte[] ENCODED_VALUE = new byte[] {
+ 0x7f, 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x69,
+ 0x6e, 0x67, (byte) 0xff
+ };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ decoder.setAutoDecodeInfinitiveUnicodeStrings(false);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example74Test.java b/src/test/java/co/nstant/in/cbor/examples/Example74Test.java
new file mode 100644
index 0000000..e3c22d5
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example74Test.java
@@ -0,0 +1,49 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.Array;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.SimpleValue;
+
+/**
+ * [_ ] -> 0x9fff
+ */
+public class Example74Test {
+
+ private static final List<DataItem> VALUE = new CborBuilder()
+ .add(new Array().setChunked(true))
+ .add(SimpleValue.BREAK)
+ .build();
+
+ private static final byte[] ENCODED_VALUE = new byte[] {
+ (byte) 0x9f, (byte) 0xff };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ decoder.setAutoDecodeInfinitiveArrays(false);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example75Test.java b/src/test/java/co/nstant/in/cbor/examples/Example75Test.java
new file mode 100644
index 0000000..ede4fce
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example75Test.java
@@ -0,0 +1,56 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.Array;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.SimpleValue;
+
+/**
+ * [_ 1, [2, 3], [_ 4, 5]] -> 0x9f018202039f0405ffff
+ */
+public class Example75Test {
+
+ private static final List<DataItem> VALUE = new CborBuilder()
+ .add(new Array().setChunked(true))
+ .add(1)
+ .addArray().add(2).add(3).end()
+ .add(new Array().setChunked(true))
+ .add(4)
+ .add(5)
+ .add(SimpleValue.BREAK)
+ .add(SimpleValue.BREAK)
+ .build();
+
+ private static final byte[] ENCODED_VALUE = new byte[] {
+ (byte) 0x9f, 0x01, (byte) 0x82, 0x02, 0x03, (byte) 0x9f,
+ 0x04, 0x05, (byte) 0xff, (byte) 0xff };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ decoder.setAutoDecodeInfinitiveArrays(false);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example76Test.java b/src/test/java/co/nstant/in/cbor/examples/Example76Test.java
new file mode 100644
index 0000000..5a0c017
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example76Test.java
@@ -0,0 +1,53 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.Array;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.SimpleValue;
+
+/**
+ * [_ 1, [2, 3], [4,5]] -> 0x9f01820203820405ff
+ */
+public class Example76Test {
+
+ private static final List<DataItem> VALUE = new CborBuilder()
+ .add(new Array().setChunked(true))
+ .add(1)
+ .addArray().add(2).add(3).end()
+ .addArray().add(4).add(5).end()
+ .add(SimpleValue.BREAK)
+ .build();
+
+ private static final byte[] ENCODED_VALUE = new byte[] {
+ (byte) 0x9f, 0x01, (byte) 0x82, 0x02, 0x03, (byte) 0x82,
+ 0x04, 0x05, (byte) 0xff };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ decoder.setAutoDecodeInfinitiveArrays(false);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example77Test.java b/src/test/java/co/nstant/in/cbor/examples/Example77Test.java
new file mode 100644
index 0000000..199cf57
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example77Test.java
@@ -0,0 +1,45 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+/**
+ * [1, [2, 3], [_ 4,5]] -> 0x83 01 82 02 03 9f 04 05 ff
+ */
+public class Example77Test {
+
+ private static final List<DataItem> VALUE = new CborBuilder().addArray()
+ .add(1).addArray().add(2).add(3).end().startArray().add(4).add(5)
+ .end().end().build();
+
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0x83, 0x01,
+ (byte) 0x82, 0x02, 0x03, (byte) 0x9f, 0x04, 0x05, (byte) 0xff };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example78Test.java b/src/test/java/co/nstant/in/cbor/examples/Example78Test.java
new file mode 100644
index 0000000..d785fb4
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example78Test.java
@@ -0,0 +1,45 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+/**
+ * [1, [_ 2, 3], [4,5]] -> 0x83019f0203ff820405
+ */
+public class Example78Test {
+
+ private static final List<DataItem> VALUE = new CborBuilder().addArray()
+ .add(1).startArray().add(2).add(3).end().addArray().add(4).add(5)
+ .end().end().build();
+
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0x83, 0x01,
+ (byte) 0x9f, 0x02, 0x03, (byte) 0xff, (byte) 0x82, 0x04, 0x05 };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example79Test.java b/src/test/java/co/nstant/in/cbor/examples/Example79Test.java
new file mode 100644
index 0000000..bb881be
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example79Test.java
@@ -0,0 +1,51 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+/**
+ * [_ 1, 2, 3, 4, 5, 6,7, 8, 9, 10, 11, 12,13, 14, 15, 16, 17,18, 19, 20, 21,
+ * 22,23, 24, 25] ->
+ * 0x9f0102030405060708090a0b0c0d0e0f101112131415161718181819ff
+ */
+public class Example79Test {
+
+ private static final List<DataItem> VALUE = new CborBuilder().startArray()
+ .add(1).add(2).add(3).add(4).add(5).add(6).add(7).add(8).add(9)
+ .add(10).add(11).add(12).add(13).add(14).add(15).add(16).add(17)
+ .add(18).add(19).add(20).add(21).add(22).add(23).add(24).add(25)
+ .end().build();
+
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0x9f, 0x01,
+ 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+ 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x18, 0x18, 0x19, (byte) 0xff };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example80Test.java b/src/test/java/co/nstant/in/cbor/examples/Example80Test.java
new file mode 100644
index 0000000..9d7c011
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example80Test.java
@@ -0,0 +1,46 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+/**
+ * {_ "a": 1, "b": [_ 2, 3]} -> 0xbf61610161629f0203ffff
+ */
+public class Example80Test {
+
+ private static final List<DataItem> VALUE = new CborBuilder().startMap()
+ .put("a", 1).put("b", 2).startArray("b").add(2).add(3).end().end()
+ .build();
+
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0xbf, 0x61,
+ 0x61, 0x01, 0x61, 0x62, (byte) 0x9f, 0x02, 0x03, (byte) 0xff,
+ (byte) 0xff };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example81Test.java b/src/test/java/co/nstant/in/cbor/examples/Example81Test.java
new file mode 100644
index 0000000..c6b0b16
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example81Test.java
@@ -0,0 +1,44 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+/**
+ * ["a", {_ "b": "c"}] -> 0x826161bf61626163ff
+ */
+public class Example81Test {
+
+ private static final List<DataItem> VALUE = new CborBuilder().addArray()
+ .add("a").startMap().put("b", "c").end().end().build();
+
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0x82, 0x61,
+ 0x61, (byte) 0xbf, 0x61, 0x62, 0x61, 0x63, (byte) 0xff };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/examples/Example82Test.java b/src/test/java/co/nstant/in/cbor/examples/Example82Test.java
new file mode 100644
index 0000000..2998438
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/examples/Example82Test.java
@@ -0,0 +1,45 @@
+package co.nstant.in.cbor.examples;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+/**
+ * {_ "Fun": true, "Amt": -2} -> 0xbf6346756ef563416d7421ff
+ */
+public class Example82Test {
+
+ private static final List<DataItem> VALUE = new CborBuilder().startMap()
+ .put("Fun", true).put("Amt", -2).end().build();
+
+ private static final byte[] ENCODED_VALUE = new byte[] { (byte) 0xbf, 0x63,
+ 0x46, 0x75, 0x6e, (byte) 0xf5, 0x63, 0x41, 0x6d, 0x74, 0x21,
+ (byte) 0xff };
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(VALUE);
+ Assert.assertArrayEquals(ENCODED_VALUE, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(ENCODED_VALUE);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ List<DataItem> dataItems = decoder.decode();
+ Assert.assertArrayEquals(VALUE.toArray(), dataItems.toArray());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/AbstractByteStringTest.java b/src/test/java/co/nstant/in/cbor/model/AbstractByteStringTest.java
new file mode 100644
index 0000000..5cf1044
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/AbstractByteStringTest.java
@@ -0,0 +1,44 @@
+package co.nstant.in.cbor.model;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.ByteString;
+import co.nstant.in.cbor.model.DataItem;
+
+public abstract class AbstractByteStringTest {
+
+ private final byte[] value;
+ private final byte[] encodedValue;
+
+ public AbstractByteStringTest(byte[] value, byte[] encodedValue) {
+ this.value = value;
+ this.encodedValue = encodedValue;
+ }
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(new ByteString(value));
+ Assert.assertArrayEquals(encodedValue, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(encodedValue);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ DataItem dataItem = decoder.decodeNext();
+ Assert.assertTrue(dataItem instanceof ByteString);
+ ByteString byteString = (ByteString) dataItem;
+ Assert.assertArrayEquals(value, byteString.getBytes());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/AbstractDataItemTest.java b/src/test/java/co/nstant/in/cbor/model/AbstractDataItemTest.java
new file mode 100644
index 0000000..a2f76b2
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/AbstractDataItemTest.java
@@ -0,0 +1,24 @@
+package co.nstant.in.cbor.model;
+
+import java.io.ByteArrayOutputStream;
+
+import org.junit.Assert;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+
+public abstract class AbstractDataItemTest {
+
+ protected void shouldEncodeAndDecode(String message, DataItem dataItem)
+ throws CborException {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteArrayOutputStream);
+ encoder.encode(dataItem);
+ byte[] bytes = byteArrayOutputStream.toByteArray();
+ DataItem object = CborDecoder.decode(bytes).get(0);
+ Assert.assertEquals(message, dataItem, object);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/AbstractDoublePrecisionFloatTest.java b/src/test/java/co/nstant/in/cbor/model/AbstractDoublePrecisionFloatTest.java
new file mode 100644
index 0000000..b851539
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/AbstractDoublePrecisionFloatTest.java
@@ -0,0 +1,47 @@
+package co.nstant.in.cbor.model;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.DoublePrecisionFloat;
+
+public abstract class AbstractDoublePrecisionFloatTest {
+
+ private final double value;
+ private final byte[] encodedValue;
+
+ public AbstractDoublePrecisionFloatTest(double value, byte[] encodedValue) {
+ this.value = value;
+ this.encodedValue = encodedValue;
+ }
+
+ @Test
+ public void shouldEncode() throws CborException {
+ List<DataItem> dataItems = new CborBuilder().add(value).build();
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(dataItems.get(0));
+ Assert.assertArrayEquals(encodedValue, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(encodedValue);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ DataItem dataItem = decoder.decodeNext();
+ Assert.assertTrue(dataItem instanceof DoublePrecisionFloat);
+ DoublePrecisionFloat doublePrecisionFloat = (DoublePrecisionFloat) dataItem;
+ Assert.assertEquals(value, doublePrecisionFloat.getValue(), 0);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/AbstractFloatTest.java b/src/test/java/co/nstant/in/cbor/model/AbstractFloatTest.java
new file mode 100644
index 0000000..873b9f3
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/AbstractFloatTest.java
@@ -0,0 +1,30 @@
+package co.nstant.in.cbor.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.util.Objects;
+
+import org.junit.Test;
+
+public class AbstractFloatTest {
+
+ @Test
+ public void testEquals() {
+ AbstractFloat a = new AbstractFloat(SpecialType.IEEE_754_SINGLE_PRECISION_FLOAT, 0.0f);
+ AbstractFloat b = new AbstractFloat(SpecialType.IEEE_754_SINGLE_PRECISION_FLOAT, 0.3f);
+ assertEquals(a, a);
+ assertEquals(b, b);
+ assertFalse(a.equals(b));
+ assertFalse(a.equals(null));
+ assertFalse(a.equals("test"));
+ }
+
+ @Test
+ public void testHashcode() {
+ Special superClass = new Special(SpecialType.IEEE_754_SINGLE_PRECISION_FLOAT);
+ AbstractFloat f = new AbstractFloat(SpecialType.IEEE_754_SINGLE_PRECISION_FLOAT, 0.0f);
+ assertEquals(superClass.hashCode() ^ Objects.hashCode(0.0f), f.hashCode());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/AbstractHalfPrecisionFloatTest.java b/src/test/java/co/nstant/in/cbor/model/AbstractHalfPrecisionFloatTest.java
new file mode 100644
index 0000000..e7fd1a2
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/AbstractHalfPrecisionFloatTest.java
@@ -0,0 +1,44 @@
+package co.nstant.in.cbor.model;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.HalfPrecisionFloat;
+
+public abstract class AbstractHalfPrecisionFloatTest {
+
+ private final float value;
+ private final byte[] encodedValue;
+
+ public AbstractHalfPrecisionFloatTest(float value, byte[] encodedValue) {
+ this.value = value;
+ this.encodedValue = encodedValue;
+ }
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(new HalfPrecisionFloat(value));
+ Assert.assertArrayEquals(encodedValue, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(encodedValue);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ DataItem dataItem = decoder.decodeNext();
+ Assert.assertTrue(dataItem instanceof HalfPrecisionFloat);
+ HalfPrecisionFloat halfPrecisionFloat = (HalfPrecisionFloat) dataItem;
+ Assert.assertEquals(value, halfPrecisionFloat.getValue(), 0);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/AbstractNumberTest.java b/src/test/java/co/nstant/in/cbor/model/AbstractNumberTest.java
new file mode 100644
index 0000000..a277497
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/AbstractNumberTest.java
@@ -0,0 +1,53 @@
+package co.nstant.in.cbor.model;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborBuilder;
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.Number;
+
+public abstract class AbstractNumberTest {
+
+ private final BigInteger value;
+ private final byte[] encodedValue;
+
+ public AbstractNumberTest(long value, byte[] encodedValue) {
+ this.value = BigInteger.valueOf(value);
+ this.encodedValue = encodedValue;
+ }
+
+ public AbstractNumberTest(BigInteger value, byte[] encodedValue) {
+ this.value = value;
+ this.encodedValue = encodedValue;
+ }
+
+ @Test
+ public void shouldEncode() throws CborException {
+ List<DataItem> dataItems = new CborBuilder().add(value).build();
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(dataItems.get(0));
+ Assert.assertArrayEquals(encodedValue, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(encodedValue);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ DataItem dataItem = decoder.decodeNext();
+ Assert.assertTrue(dataItem instanceof Number);
+ Number number = (Number) dataItem;
+ Assert.assertEquals(value, number.getValue());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/AbstractSinglePrecisionFloatTest.java b/src/test/java/co/nstant/in/cbor/model/AbstractSinglePrecisionFloatTest.java
new file mode 100644
index 0000000..30b6ec3
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/AbstractSinglePrecisionFloatTest.java
@@ -0,0 +1,44 @@
+package co.nstant.in.cbor.model;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.SinglePrecisionFloat;
+
+public abstract class AbstractSinglePrecisionFloatTest {
+
+ private final float value;
+ private final byte[] encodedValue;
+
+ public AbstractSinglePrecisionFloatTest(float value, byte[] encodedValue) {
+ this.value = value;
+ this.encodedValue = encodedValue;
+ }
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(new SinglePrecisionFloat(value));
+ Assert.assertArrayEquals(encodedValue, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(encodedValue);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ DataItem dataItem = decoder.decodeNext();
+ Assert.assertTrue(dataItem instanceof SinglePrecisionFloat);
+ SinglePrecisionFloat singlePrecisionFloat = (SinglePrecisionFloat) dataItem;
+ Assert.assertEquals(value, singlePrecisionFloat.getValue(), 0);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/AbstractStringTest.java b/src/test/java/co/nstant/in/cbor/model/AbstractStringTest.java
new file mode 100644
index 0000000..77b416c
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/AbstractStringTest.java
@@ -0,0 +1,44 @@
+package co.nstant.in.cbor.model;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborDecoder;
+import co.nstant.in.cbor.CborEncoder;
+import co.nstant.in.cbor.CborException;
+import co.nstant.in.cbor.model.DataItem;
+import co.nstant.in.cbor.model.UnicodeString;
+
+public abstract class AbstractStringTest {
+
+ private final String value;
+ private final byte[] encodedValue;
+
+ public AbstractStringTest(String value, byte[] encodedValue) {
+ this.value = value;
+ this.encodedValue = encodedValue;
+ }
+
+ @Test
+ public void shouldEncode() throws CborException {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ CborEncoder encoder = new CborEncoder(byteOutputStream);
+ encoder.encode(new UnicodeString(value));
+ Assert.assertArrayEquals(encodedValue, byteOutputStream.toByteArray());
+ }
+
+ @Test
+ public void shouldDecode() throws CborException {
+ InputStream inputStream = new ByteArrayInputStream(encodedValue);
+ CborDecoder decoder = new CborDecoder(inputStream);
+ DataItem dataItem = decoder.decodeNext();
+ Assert.assertTrue(dataItem instanceof UnicodeString);
+ UnicodeString unicodeString = (UnicodeString) dataItem;
+ Assert.assertEquals(value, unicodeString.toString());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/AdditionalInformationTest.java b/src/test/java/co/nstant/in/cbor/model/AdditionalInformationTest.java
new file mode 100644
index 0000000..465926b
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/AdditionalInformationTest.java
@@ -0,0 +1,21 @@
+package co.nstant.in.cbor.model;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class AdditionalInformationTest {
+
+ /**
+ * Additional information values 28 to 30 are reserved for future expansion.
+ */
+ @Test
+ public void shouldHandleReserved28() {
+ Assert.assertEquals(AdditionalInformation.RESERVED,
+ AdditionalInformation.ofByte(28));
+ Assert.assertEquals(AdditionalInformation.RESERVED,
+ AdditionalInformation.ofByte(29));
+ Assert.assertEquals(AdditionalInformation.RESERVED,
+ AdditionalInformation.ofByte(30));
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/ArrayTest.java b/src/test/java/co/nstant/in/cbor/model/ArrayTest.java
new file mode 100644
index 0000000..179958e
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/ArrayTest.java
@@ -0,0 +1,36 @@
+package co.nstant.in.cbor.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import org.junit.Test;
+
+public class ArrayTest {
+
+ @Test
+ public void testEquals() {
+ Array array = new Array();
+ assertEquals(array, array);
+ assertNotEquals(array, null);
+ }
+
+ @Test
+ public void testHashcode() {
+ Array array1 = new Array().add(new UnicodeString("string"));
+ Array array2 = new Array().add(new UnicodeString("string"));
+ assertEquals(array1.hashCode(), array2.hashCode());
+ }
+
+ @Test
+ public void testToString() {
+ Array array = new Array().add(new UnicodeString("a"));
+ assertEquals("[a]", array.toString());
+ array.setChunked(true);
+ assertEquals("[_ a]", array.toString());
+ array.add(new UnicodeString("b"));
+ assertEquals("[_ a, b]", array.toString());
+ array.setChunked(false);
+ assertEquals("[a, b]", array.toString());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/ByteStringTest.java b/src/test/java/co/nstant/in/cbor/model/ByteStringTest.java
new file mode 100644
index 0000000..7911f3d
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/ByteStringTest.java
@@ -0,0 +1,55 @@
+package co.nstant.in.cbor.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborException;
+
+public class ByteStringTest extends AbstractDataItemTest {
+
+ @Test
+ public void testByteString() throws CborException {
+ shouldEncodeAndDecode("1-byte array", new ByteString(
+ new byte[] { (byte) 0x00 }));
+ }
+
+ @Test
+ public void testUnicodeString() throws CborException {
+ shouldEncodeAndDecode("string", new UnicodeString("hello world"));
+ }
+
+ @Test
+ public void shouldEquals() {
+ byte[] bytes = "string".getBytes();
+ ByteString byteString = new ByteString(bytes);
+ assertTrue(byteString.equals(byteString));
+ }
+
+ @Test
+ public void shouldNotEquals() {
+ byte[] bytes = "string".getBytes();
+ ByteString byteString = new ByteString(bytes);
+ assertFalse(byteString.equals(new Object()));
+ }
+
+ @Test
+ public void shouldHashcode() {
+ ChunkableDataItem superClass = new ChunkableDataItem(MajorType.BYTE_STRING);
+ byte[] bytes = "string".getBytes();
+ ByteString byteString = new ByteString(bytes);
+ assertEquals(byteString.hashCode(), superClass.hashCode() ^ Arrays.hashCode(bytes));
+ }
+
+ @Test
+ public void shouldNotClone() {
+ byte[] bytes = "see issue #18".getBytes();
+ ByteString byteString = new ByteString(bytes);
+ assertEquals(byteString.getBytes(), bytes);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/ChunkableDataItemTest.java b/src/test/java/co/nstant/in/cbor/model/ChunkableDataItemTest.java
new file mode 100644
index 0000000..0db1264
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/ChunkableDataItemTest.java
@@ -0,0 +1,29 @@
+package co.nstant.in.cbor.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import org.junit.Test;
+
+public class ChunkableDataItemTest {
+
+ private class TestDataItem extends ChunkableDataItem {
+
+ protected TestDataItem() {
+ super(MajorType.INVALID);
+ }
+
+ }
+
+ @Test
+ public void testEquals() {
+ TestDataItem item1 = new TestDataItem();
+ TestDataItem item2 = new TestDataItem();
+ assertEquals(item1, item2);
+ item1.setChunked(true);
+ item2.setChunked(false);
+ assertFalse(item1.equals(item2));
+ assertFalse(item1.equals(null));
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/DataItemTest.java b/src/test/java/co/nstant/in/cbor/model/DataItemTest.java
new file mode 100644
index 0000000..fc7f344
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/DataItemTest.java
@@ -0,0 +1,90 @@
+package co.nstant.in.cbor.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class DataItemTest {
+
+ private class TestDataItem extends DataItem {
+
+ protected TestDataItem() {
+ super(MajorType.INVALID);
+ }
+
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void shouldThrowNullPointerException() {
+ new DataItem(null);
+ }
+
+ @Test
+ public void testSetTag_Long() {
+ DataItem di = new DataItem(MajorType.UNSIGNED_INTEGER);
+ di.setTag(1);
+ assertNotNull(di.getTag());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testSetTag_Long_negative() {
+ DataItem di = new DataItem(MajorType.UNSIGNED_INTEGER);
+ di.setTag(-1);
+ }
+
+ @Test
+ public void testSetTag_Tag() {
+ DataItem di = new DataItem(MajorType.UNSIGNED_INTEGER);
+ di.setTag(new Tag(1));
+ assertNotNull(di.getTag());
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testSetTag_Tag_null() {
+ DataItem di = new DataItem(MajorType.UNSIGNED_INTEGER);
+ di.setTag(null);
+ }
+
+ @Test
+ public void testGetTag() {
+ DataItem di = new DataItem(MajorType.UNSIGNED_INTEGER);
+ di.setTag(new Tag(1));
+
+ Tag t = di.getTag();
+ assertEquals(1L, t.getValue());
+ }
+
+ @Test
+ public void testHasTag() {
+ DataItem di = new DataItem(MajorType.UNSIGNED_INTEGER);
+ assertFalse(di.hasTag());
+
+ di.setTag(new Tag(1));
+ assertTrue(di.hasTag());
+ }
+
+ @Test
+ public void testRemoveTag() {
+ DataItem di = new DataItem(MajorType.UNSIGNED_INTEGER);
+ di.setTag(new Tag(1));
+ assertNotNull(di.getTag());
+
+ di.removeTag();
+ assertNull(di.getTag());
+ }
+
+ @Test
+ public void testEquals() {
+ DataItem a = new TestDataItem();
+ DataItem b = new TestDataItem();
+ assertEquals(a, b);
+ a.setTag(1);
+ assertFalse(a.equals(b));
+ assertFalse(a.equals(null));
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/DoublePrecisionFloatTest.java b/src/test/java/co/nstant/in/cbor/model/DoublePrecisionFloatTest.java
new file mode 100644
index 0000000..1cb20fa
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/DoublePrecisionFloatTest.java
@@ -0,0 +1,41 @@
+package co.nstant.in.cbor.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.util.Objects;
+
+import org.junit.Test;
+
+public class DoublePrecisionFloatTest {
+
+ @Test
+ public void testEquals() {
+ DoublePrecisionFloat a = new DoublePrecisionFloat(1.234);
+ DoublePrecisionFloat b = new DoublePrecisionFloat(0.333);
+ assertEquals(a, a);
+ assertEquals(b, b);
+ }
+
+ @Test
+ public void testNotEquals() {
+ DoublePrecisionFloat doublePrecisionFloat = new DoublePrecisionFloat(1.234);
+ assertFalse(doublePrecisionFloat.equals(null));
+ assertFalse(doublePrecisionFloat.equals(new DoublePrecisionFloat(1.2345)));
+ }
+
+ @Test
+ public void testHashcode() {
+ Special superClass = new Special(SpecialType.IEEE_754_DOUBLE_PRECISION_FLOAT);
+ double value = 1.234;
+ DoublePrecisionFloat doublePrecisionFloat = new DoublePrecisionFloat(value);
+ assertEquals(superClass.hashCode() ^ Objects.hashCode(value), doublePrecisionFloat.hashCode());
+ }
+
+ @Test
+ public void testToString() {
+ DoublePrecisionFloat doublePrecisionFloat = new DoublePrecisionFloat(1.234);
+ assertEquals("1.234", doublePrecisionFloat.toString());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/LanguageTaggedStringTest.java b/src/test/java/co/nstant/in/cbor/model/LanguageTaggedStringTest.java
new file mode 100644
index 0000000..a419762
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/LanguageTaggedStringTest.java
@@ -0,0 +1,17 @@
+package co.nstant.in.cbor.model;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class LanguageTaggedStringTest {
+
+ @Test
+ public void shouldInitializeWithStrings() {
+ LanguageTaggedString lts = new LanguageTaggedString("en", "Hello");
+ assertEquals(38, lts.getTag().getValue());
+ assertEquals("en", lts.getLanguage().getString());
+ assertEquals("Hello", lts.getString().getString());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/MajorTypeTest.java b/src/test/java/co/nstant/in/cbor/model/MajorTypeTest.java
new file mode 100644
index 0000000..5ee5ff2
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/MajorTypeTest.java
@@ -0,0 +1,57 @@
+package co.nstant.in.cbor.model;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class MajorTypeTest {
+
+ @Test
+ public void shouldParseUnsignedInteger() {
+ Assert.assertEquals(MajorType.UNSIGNED_INTEGER,
+ MajorType.ofByte(0b000_00000));
+ }
+
+ @Test
+ public void shouldParseNegativeInteger() {
+ Assert.assertEquals(MajorType.NEGATIVE_INTEGER,
+ MajorType.ofByte(0b001_00000));
+ }
+
+ @Test
+ public void shouldParseByteString() {
+ Assert.assertEquals(MajorType.BYTE_STRING,
+ MajorType.ofByte(0b010_00000));
+ }
+
+ @Test
+ public void shouldParseUnicodeString() {
+ Assert.assertEquals(MajorType.UNICODE_STRING,
+ MajorType.ofByte(0b011_00000));
+ }
+
+ @Test
+ public void shouldParseArray() {
+ Assert.assertEquals(MajorType.ARRAY, MajorType.ofByte(0b100_00000));
+ }
+
+ @Test
+ public void shouldParseMap() {
+ Assert.assertEquals(MajorType.MAP, MajorType.ofByte(0b101_00000));
+ }
+
+ @Test
+ public void shouldParseTag() {
+ Assert.assertEquals(MajorType.TAG, MajorType.ofByte(0b110_00000));
+ }
+
+ @Test
+ public void shouldParseSpecial() {
+ Assert.assertEquals(MajorType.SPECIAL, MajorType.ofByte(0b111_00000));
+ }
+
+ @Test
+ public void shouldReturnInvalidOnInvalidByteValue() {
+ Assert.assertEquals(MajorType.INVALID, MajorType.ofByte(0xffffffff));
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/MapTest.java b/src/test/java/co/nstant/in/cbor/model/MapTest.java
new file mode 100644
index 0000000..a77a0a6
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/MapTest.java
@@ -0,0 +1,49 @@
+package co.nstant.in.cbor.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import org.junit.Test;
+
+public class MapTest {
+
+ @Test
+ public void testRemove() {
+ UnicodeString key = new UnicodeString("key");
+ UnicodeString value = new UnicodeString("value");
+ Map map = new Map();
+ map.put(key, value);
+ assertEquals(1, map.getValues().size());
+ map.remove(key);
+ assertEquals(0, map.getValues().size());
+ }
+
+ @Test
+ public void testEquals() {
+ Map map1 = new Map();
+ assertEquals(map1, map1);
+ assertNotEquals(map1, new Object());
+ }
+
+ @Test
+ public void testHashcode() {
+ Map map1 = new Map();
+ Map map2 = new Map();
+ assertEquals(map1.hashCode(), map2.hashCode());
+ map1.put(new UnicodeString("key"), new UnicodeString("value"));
+ assertNotEquals(map1.hashCode(), map2.hashCode());
+ }
+
+ @Test
+ public void testToString() {
+ Map map = new Map();
+ assertEquals("{ }", map.toString());
+ map.put(new UnicodeString("key1"), new UnicodeString("value1"));
+ assertEquals("{ key1: value1 }", map.toString());
+ map.put(new UnicodeString("key2"), new UnicodeString("value2"));
+ assertEquals("{ key1: value1, key2: value2 }", map.toString());
+ map.setChunked(true);
+ assertEquals("{_ key1: value1, key2: value2 }", map.toString());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/NegativeIntegerTest.java b/src/test/java/co/nstant/in/cbor/model/NegativeIntegerTest.java
new file mode 100644
index 0000000..b99198f
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/NegativeIntegerTest.java
@@ -0,0 +1,26 @@
+package co.nstant.in.cbor.model;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborException;
+
+public class NegativeIntegerTest extends AbstractDataItemTest {
+
+ @Test
+ public void shouldEncodeAndDecode() throws CborException {
+ long maxInteger = -4_294_967_295L;
+ for (long i = -1L; i >= maxInteger; i += (maxInteger / 100_000L)) {
+ shouldEncodeAndDecode(String.valueOf(i), new NegativeInteger(i));
+ }
+ shouldEncodeAndDecode(String.valueOf(maxInteger), new NegativeInteger(maxInteger));
+
+ // Test for issue #1: Creation of 64-bit NegativeInteger >= -4294967296L fails
+ shouldEncodeAndDecode("Long.MIN_VALUE", new NegativeInteger(Long.MIN_VALUE));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldNotAcceptPositiveValues() {
+ new NegativeInteger(0);
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/RationalNumberTest.java b/src/test/java/co/nstant/in/cbor/model/RationalNumberTest.java
new file mode 100644
index 0000000..0a234f1
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/RationalNumberTest.java
@@ -0,0 +1,35 @@
+package co.nstant.in.cbor.model;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborException;
+
+public class RationalNumberTest {
+
+ @Test(expected = CborException.class)
+ public void shouldThrowIfNumeratorIsNull() throws CborException {
+ new RationalNumber(null, new UnsignedInteger(1));
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowIfDenominatorIsNull() throws CborException {
+ new RationalNumber(new UnsignedInteger(1), null);
+ }
+
+ @Test(expected = CborException.class)
+ public void shouldThrowIfDenominatorIsZero() throws CborException {
+ new RationalNumber(new UnsignedInteger(1), new UnsignedInteger(0));
+ }
+
+ @Test
+ public void shouldSetNumeratorAndDenominator() throws CborException {
+ UnsignedInteger one = new UnsignedInteger(1);
+ UnsignedInteger two = new UnsignedInteger(2);
+ RationalNumber rationalNumber = new RationalNumber(one, two);
+ assertEquals(one, rationalNumber.getNumerator());
+ assertEquals(two, rationalNumber.getDenominator());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/SimpleValueTest.java b/src/test/java/co/nstant/in/cbor/model/SimpleValueTest.java
new file mode 100644
index 0000000..d77fc32
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/SimpleValueTest.java
@@ -0,0 +1,47 @@
+package co.nstant.in.cbor.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Objects;
+
+import org.junit.Test;
+
+public class SimpleValueTest {
+
+ @Test
+ public void testHashcode() {
+ Special superClass1 = new Special(SpecialType.SIMPLE_VALUE);
+ Special superClass2 = new Special(SpecialType.SIMPLE_VALUE_NEXT_BYTE);
+ for (int i = 1; i < 256; i++) {
+ SimpleValue simpleValue = new SimpleValue(i);
+ if (i <= 23) {
+ assertEquals(simpleValue.hashCode(), superClass1.hashCode() ^ Objects.hashCode(i));
+ } else {
+ assertEquals(simpleValue.hashCode(), superClass2.hashCode() ^ Objects.hashCode(i));
+ }
+ }
+ }
+
+ @Test
+ public void testEquals1() {
+ for (int i = 0; i < 256; i++) {
+ SimpleValue simpleValue1 = new SimpleValue(i);
+ SimpleValue simpleValue2 = new SimpleValue(i);
+ assertTrue(simpleValue1.equals(simpleValue2));
+ }
+ }
+
+ @Test
+ public void testEquals2() {
+ SimpleValue simpleValue = new SimpleValue(0);
+ assertFalse(simpleValue.equals(new SimpleValue(1)));
+ assertFalse(simpleValue.equals(null));
+ assertFalse(simpleValue.equals(false));
+ assertFalse(simpleValue.equals(""));
+ assertFalse(simpleValue.equals(1));
+ assertFalse(simpleValue.equals(1.1));
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/SpecialTest.java b/src/test/java/co/nstant/in/cbor/model/SpecialTest.java
new file mode 100644
index 0000000..de945c8
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/SpecialTest.java
@@ -0,0 +1,15 @@
+package co.nstant.in.cbor.model;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class SpecialTest {
+
+ @Test
+ public void testToString() {
+ Special special = Special.BREAK;
+ assertEquals("BREAK", special.toString());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/SpecialTypeTest.java b/src/test/java/co/nstant/in/cbor/model/SpecialTypeTest.java
new file mode 100644
index 0000000..1d530c7
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/SpecialTypeTest.java
@@ -0,0 +1,15 @@
+package co.nstant.in.cbor.model;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class SpecialTypeTest {
+
+ @Test
+ public void shouldDetectUnallocated() {
+ Assert.assertTrue(SpecialType.ofByte(28).equals(SpecialType.UNALLOCATED));
+ Assert.assertTrue(SpecialType.ofByte(29).equals(SpecialType.UNALLOCATED));
+ Assert.assertTrue(SpecialType.ofByte(30).equals(SpecialType.UNALLOCATED));
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/TagTest.java b/src/test/java/co/nstant/in/cbor/model/TagTest.java
new file mode 100644
index 0000000..e4ad8f8
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/TagTest.java
@@ -0,0 +1,54 @@
+package co.nstant.in.cbor.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Objects;
+
+import org.junit.Test;
+
+public class TagTest {
+
+ @Test
+ public void testHashcode() {
+ DataItem superClass = new DataItem(MajorType.TAG);
+ for (long i = 0; i < 256; i++) {
+ Tag tag = new Tag(i);
+ assertEquals(tag.hashCode(), superClass.hashCode() ^ Objects.hashCode(i));
+ }
+ }
+
+ @Test
+ public void testEquals1() {
+ for (int i = 0; i < 256; i++) {
+ Tag tag1 = new Tag(i);
+ Tag tag2 = new Tag(i);
+ assertTrue(tag1.equals(tag2));
+ }
+ }
+
+ @Test
+ public void testEquals2() {
+ Tag tag = new Tag(0);
+ assertTrue(tag.equals(tag));
+ }
+
+ @Test
+ public void testNotEquals() {
+ Tag tag = new Tag(0);
+ assertFalse(tag.equals(new Tag(1)));
+ assertFalse(tag.equals(null));
+ assertFalse(tag.equals(false));
+ assertFalse(tag.equals(""));
+ assertFalse(tag.equals(1));
+ assertFalse(tag.equals(1.1));
+ }
+
+ @Test
+ public void testToString() {
+ assertEquals("Tag(0)", new Tag(0).toString());
+ assertEquals("Tag(123)", new Tag(123).toString());
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/UnicodeStringTest.java b/src/test/java/co/nstant/in/cbor/model/UnicodeStringTest.java
new file mode 100644
index 0000000..27b820b
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/UnicodeStringTest.java
@@ -0,0 +1,55 @@
+package co.nstant.in.cbor.model;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class UnicodeStringTest {
+
+ @Test
+ public void toStringShouldPrintNull() {
+ Assert.assertEquals("null", new UnicodeString(null).toString());
+ }
+
+ @Test
+ public void shouldEqualsSameObject() {
+ UnicodeString unicodeString = new UnicodeString("string");
+ Assert.assertTrue(unicodeString.equals(unicodeString));
+ }
+
+ @Test
+ public void shouldEqualsBothNull() {
+ UnicodeString unicodeString1 = new UnicodeString(null);
+ UnicodeString unicodeString2 = new UnicodeString(null);
+ Assert.assertTrue(unicodeString1.equals(unicodeString2));
+ Assert.assertTrue(unicodeString2.equals(unicodeString1));
+ }
+
+ @Test
+ public void shouldEqualsSameValue() {
+ UnicodeString unicodeString1 = new UnicodeString("string");
+ UnicodeString unicodeString2 = new UnicodeString("string");
+ Assert.assertTrue(unicodeString1.equals(unicodeString2));
+ Assert.assertTrue(unicodeString2.equals(unicodeString1));
+ }
+
+ @Test
+ public void shouldHashNull() {
+ Assert.assertEquals(0, new UnicodeString(null).hashCode());
+ }
+
+ @Test
+ public void shouldNotEqualOtherObjects() {
+ UnicodeString unicodeString = new UnicodeString("string");
+ Assert.assertFalse(unicodeString.equals(null));
+ Assert.assertFalse(unicodeString.equals(1));
+ Assert.assertFalse(unicodeString.equals("string"));
+ }
+
+ @Test
+ public void shouldNotEquals() {
+ UnicodeString unicodeString1 = new UnicodeString(null);
+ UnicodeString unicodeString2 = new UnicodeString("");
+ Assert.assertFalse(unicodeString1.equals(unicodeString2));
+ }
+
+}
diff --git a/src/test/java/co/nstant/in/cbor/model/UnsignedIntegerTest.java b/src/test/java/co/nstant/in/cbor/model/UnsignedIntegerTest.java
new file mode 100644
index 0000000..06b3541
--- /dev/null
+++ b/src/test/java/co/nstant/in/cbor/model/UnsignedIntegerTest.java
@@ -0,0 +1,62 @@
+package co.nstant.in.cbor.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.math.BigInteger;
+
+import org.junit.Test;
+
+import co.nstant.in.cbor.CborException;
+
+public class UnsignedIntegerTest extends AbstractDataItemTest {
+
+ @Test
+ public void shouldEncodeAndDecode() throws CborException {
+ long maxInteger = 4_294_967_295L;
+ for (long i = 0L; i < maxInteger; i += (maxInteger / 100_000L)) {
+ shouldEncodeAndDecode(String.valueOf(i), new UnsignedInteger(i));
+ }
+ shouldEncodeAndDecode(String.valueOf(maxInteger), new UnsignedInteger(maxInteger));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldNotAcceptNegativeValues() {
+ new UnsignedInteger(-1);
+ }
+
+ @Test
+ public void testToString() {
+ UnsignedInteger unsignedInteger = new UnsignedInteger(BigInteger.ZERO);
+ assertEquals("0", unsignedInteger.toString());
+ }
+
+ @Test
+ public void testEquals1() {
+ UnsignedInteger unsignedInteger = new UnsignedInteger(BigInteger.ZERO);
+ assertTrue(unsignedInteger.equals(unsignedInteger));
+ }
+
+ @Test
+ public void testEquals2() {
+ for (int i = 0; i < 256; i++) {
+ UnsignedInteger unsignedInteger1 = new UnsignedInteger(BigInteger.valueOf(i));
+ UnsignedInteger unsignedInteger2 = new UnsignedInteger(BigInteger.valueOf(i));
+ assertTrue(unsignedInteger1.equals(unsignedInteger2));
+ }
+ }
+
+ @Test
+ public void testEquals3() {
+ UnsignedInteger unsignedInteger = new UnsignedInteger(BigInteger.ZERO);
+ assertFalse(unsignedInteger.equals(new Object()));
+ }
+
+ @Test
+ public void testHashcode() {
+ UnsignedInteger unsignedInteger = new UnsignedInteger(BigInteger.ZERO);
+ assertEquals(BigInteger.ZERO.hashCode(), unsignedInteger.getValue().hashCode());
+ }
+
+}