/*
* Copyright 2016 MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.bson;
import org.bson.codecs.BsonDocumentCodec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;
import org.bson.io.BasicOutputBuffer;
import org.bson.types.Decimal128;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import util.Hex;
import util.JsonPoweredTestHelper;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static java.lang.String.format;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
// BSON tests powered by language-agnostic JSON-based tests included in test resources
@RunWith(Parameterized.class)
public class GenericBsonDecimal128Test {
enum TestCaseType {
VALID,
PARSE_ERROR
}
private final BsonDocument testDefinition;
private final BsonDocument testCase;
private final TestCaseType testCaseType;
public GenericBsonDecimal128Test(final String description, final BsonDocument testDefinition, final BsonDocument testCase,
final TestCaseType testCaseType) {
this.testDefinition = testDefinition;
this.testCase = testCase;
this.testCaseType = testCaseType;
}
@Test
public void shouldPassAllOutcomes() {
switch (testCaseType) {
case VALID:
runValid();
break;
case PARSE_ERROR:
runParseError();
break;
default:
throw new IllegalArgumentException(format("Unsupported test case type %s", testCaseType));
}
}
private void runValid() {
String bsonHex = testCase.getString("bson").getValue().toUpperCase();
String json = testCase.getString("extjson").getValue();
String canonicalJson = testCase.getString("canonical_extjson", new BsonString(json)).getValue();
String description = testCase.getString("description").getValue();
boolean lossy = testCase.getBoolean("lossy", new BsonBoolean(false)).getValue();
BsonDocument decodedDocument = decodeToDocument(bsonHex, description);
// B -> B
assertEquals(format("Failed to create expected BSON for document with description '%s'", description),
bsonHex, encodeToHex(decodedDocument));
// B -> E
assertEquals(format("Failed to create expected JSON for document with description '%s'", description),
stripWhiteSpace(canonicalJson), stripWhiteSpace(decodedDocument.toJson()));
// E -> E
BsonDocument parsedDocument = BsonDocument.parse(json);
assertEquals(format("Failed to parse expected JSON for document with description '%s'", description),
stripWhiteSpace(canonicalJson), stripWhiteSpace(parsedDocument.toJson()));
if (!lossy) {
// E -> B
assertEquals(format("Failed to create expected BsonDocument for parsed canonical JSON document with description '%s'",
description), decodedDocument, parsedDocument);
assertEquals(format("Failed to create expected BSON for parsed JSON document with description '%s'", description),
bsonHex, encodeToHex(parsedDocument));
}
if (!canonicalJson.equals(json)) {
BsonDocument parsedCanonicalDocument = BsonDocument.parse(canonicalJson);
// E -> E
assertEquals(format("Failed to create expected JSON for parsed canonical JSON document with description '%s'", description),
stripWhiteSpace(canonicalJson), stripWhiteSpace(parsedCanonicalDocument.toJson()));
if (!lossy) {
// E -> B
assertEquals(format("Failed to create expected BsonDocument for parsed canonical JSON document with description '%s'",
description), decodedDocument, parsedCanonicalDocument);
assertEquals(format("Failed to create expected BSON for parsed canonical JSON document with description '%s'", description),
bsonHex, encodeToHex(parsedDocument));
}
}
}
private BsonDocument decodeToDocument(final String subjectHex, final String description) {
ByteBuffer byteBuffer = ByteBuffer.wrap(Hex.decode(subjectHex));
BsonDocument actualDecodedDocument = new BsonDocumentCodec().decode(new BsonBinaryReader(byteBuffer),
DecoderContext.builder().build());
if (byteBuffer.hasRemaining()) {
fail(format("Should have consumed all bytes, but " + byteBuffer.remaining() + " still remain in the buffer "
+ "for document with description ", description));
}
return actualDecodedDocument;
}
private String encodeToHex(final BsonDocument decodedDocument) {
BasicOutputBuffer outputBuffer = new BasicOutputBuffer();
new BsonDocumentCodec().encode(new BsonBinaryWriter(outputBuffer), decodedDocument, EncoderContext.builder().build());
return Hex.encode(outputBuffer.toByteArray());
}
private void runParseError() {
try {
String description = testCase.getString("description").getValue();
Decimal128.parse(testCase.getString("string").getValue());
fail(format("Should have failed parsing for subject with description '%s'", description));
} catch (NumberFormatException e) {
// all good
} catch (IllegalArgumentException e) {
// all good
}
}
@Parameterized.Parameters(name = "{0}")
public static Collection<Object[]> data() throws URISyntaxException, IOException {
List<Object[]> data = new ArrayList<Object[]>();
for (File file : JsonPoweredTestHelper.getTestFiles("/decimal128")) {
BsonDocument testDocument = JsonPoweredTestHelper.getTestDocument(file);
for (BsonValue curValue : testDocument.getArray("valid", new BsonArray())) {
BsonDocument testCaseDocument = curValue.asDocument();
data.add(new Object[]{createTestCaseDescription(testDocument, testCaseDocument, "valid"), testDocument, testCaseDocument,
TestCaseType.VALID});
}
for (BsonValue curValue : testDocument.getArray("parseErrors", new BsonArray())) {
BsonDocument testCaseDocument = curValue.asDocument();
data.add(new Object[]{createTestCaseDescription(testDocument, testCaseDocument, "parseError"), testDocument,
testCaseDocument, TestCaseType.PARSE_ERROR});
}
}
return data;
}
private static String createTestCaseDescription(final BsonDocument testDocument, final BsonDocument testCaseDocument,
final String testCaseType) {
return testDocument.getString("description").getValue()
+ "[" + testCaseType + "]"
+ ": " + testCaseDocument.getString("description").getValue();
}
private String stripWhiteSpace(final String json) {
return json.replace(" ", "");
}
}