8 changed files with 409 additions and 79 deletions
@ -0,0 +1,138 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2003-2014 the original author or authors. |
||||||
|
* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
import groovy.text.markup.MarkupTemplateEngine |
||||||
|
import groovy.text.markup.TemplateConfiguration |
||||||
|
|
||||||
|
|
||||||
|
buildscript { |
||||||
|
// this block should not be necessary, but for some reason it fails without! |
||||||
|
repositories { |
||||||
|
jcenter() |
||||||
|
} |
||||||
|
|
||||||
|
dependencies { |
||||||
|
classpath 'me.champeau.gradle:japicmp-gradle-plugin:0.1.0' |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
task checkBinaryCompatibility { |
||||||
|
description = 'Generates binary compatibility reports' |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
if (JavaVersion.current().isJava7Compatible()) { |
||||||
|
apply plugin: 'me.champeau.gradle.japicmp' |
||||||
|
|
||||||
|
def referenceMinorVersion = '1.1.0' |
||||||
|
|
||||||
|
def reportGenerator = { model -> |
||||||
|
outputProcessor { |
||||||
|
|
||||||
|
def skipClass = { c -> c.fullyQualifiedName.startsWith('com.jayway.jsonpath.internal') || c.fullyQualifiedName.contains('$')} |
||||||
|
def skipMethod = { c, m -> skipClass(c) || m.name =~ /access\$[0-9]+/ } |
||||||
|
def violations = [:].withDefault { |
||||||
|
// key = class name |
||||||
|
// value = map of violations |
||||||
|
[:].withDefault { [] } |
||||||
|
} |
||||||
|
removedMethod { c, m -> |
||||||
|
if (!skipMethod(c, m)) { |
||||||
|
def level = m.name.startsWith('super$') ? 'warning' : 'error' |
||||||
|
violations[c.fullyQualifiedName][level] << "Method ${m.name} has been removed" |
||||||
|
} |
||||||
|
} |
||||||
|
removedClass { c -> |
||||||
|
if (!skipClass(c)) { |
||||||
|
violations[c.fullyQualifiedName].error << "Class has been removed" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
modifiedMethod { c, m -> |
||||||
|
if (!skipMethod(c, m)) { |
||||||
|
violations[c.fullyQualifiedName].warning << """<p>Method ${m.name} has been modified</p> |
||||||
|
<p>From <pre>${m.oldMethod.get()?.longName}</pre> to <pre>${m.newMethod.get()?.longName}</pre></p>""" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
newClass { c -> |
||||||
|
if (!skipClass(c)) { |
||||||
|
violations[c.fullyQualifiedName].info << "Class has been added" |
||||||
|
} |
||||||
|
} |
||||||
|
newMethod { c, m -> |
||||||
|
if (!skipMethod(c, m)) { |
||||||
|
violations[c.fullyQualifiedName].info << """<p>Method ${m.name} has been added</p> |
||||||
|
<p>Signature: <pre>${m.newMethod.get()?.longName}</pre></p>""" |
||||||
|
} |
||||||
|
} |
||||||
|
after { |
||||||
|
model.violations = violations |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// using a global engine for all tasks in order to increase performance |
||||||
|
def configDir = file("$rootDir/gradle") |
||||||
|
def templateFile = 'binarycompat-report.groovy' |
||||||
|
def templateConfiguration = new TemplateConfiguration() |
||||||
|
templateConfiguration.with { |
||||||
|
autoIndent = true |
||||||
|
autoNewLine = true |
||||||
|
} |
||||||
|
def engine = new MarkupTemplateEngine(this.class.classLoader, configDir, templateConfiguration) |
||||||
|
|
||||||
|
|
||||||
|
subprojects { |
||||||
|
|
||||||
|
task japicmp(type: me.champeau.gradle.ArtifactJapicmpTask) { |
||||||
|
dependsOn jar |
||||||
|
//baseline = "com.jayway.jsonpath:${project.name}:${referenceMinorVersion}@jar" |
||||||
|
baseline = "com.jayway.jsonpath:${project.name}:+@jar" |
||||||
|
to = jar.archivePath |
||||||
|
accessModifier = 'protected' |
||||||
|
onlyModified = true |
||||||
|
failOnModification = false |
||||||
|
txtOutputFile = file("$buildDir/reports/japi.txt") |
||||||
|
|
||||||
|
def htmlReportFile = file("${buildDir}/reports/binary-compat-${project.name}.html") |
||||||
|
inputs.file file("$configDir/$templateFile") |
||||||
|
inputs.file templateFile |
||||||
|
outputs.file htmlReportFile |
||||||
|
|
||||||
|
def model = [title : "Binary compatibility report for ${project.name}", |
||||||
|
project : project, |
||||||
|
baseline: baseline, |
||||||
|
archive : to.name] |
||||||
|
outputProcessor(reportGenerator.curry(model)) |
||||||
|
|
||||||
|
doLast { |
||||||
|
htmlReportFile.withWriter('utf-8') { wrt -> |
||||||
|
engine.createTemplateByPath(templateFile).make(model).writeTo(wrt) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
subprojects { |
||||||
|
check.dependsOn(checkBinaryCompatibility) |
||||||
|
tasks.withType(me.champeau.gradle.ArtifactJapicmpTask) { task -> |
||||||
|
checkBinaryCompatibility.dependsOn(task) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,153 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2003-2014 the original author or authors. |
||||||
|
* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* A template which generates an HTML report from the bincompat XML report |
||||||
|
*/ |
||||||
|
modelTypes = { |
||||||
|
String title |
||||||
|
String baseline |
||||||
|
String archive |
||||||
|
Map<String,Map<String,List<String>>> violations |
||||||
|
} |
||||||
|
|
||||||
|
def severityMapping = [ |
||||||
|
error : 'danger', |
||||||
|
warning: 'warning', |
||||||
|
info : 'info', |
||||||
|
ignore : 'success' |
||||||
|
] |
||||||
|
|
||||||
|
yieldUnescaped '<!DOCTYPE html>' |
||||||
|
|
||||||
|
|
||||||
|
html { |
||||||
|
head { |
||||||
|
meta 'charset': "utf-8" |
||||||
|
meta 'http-equiv': "content-type", content: "text/html; charset=utf-8" |
||||||
|
meta 'http-equiv': "X-UA-Compatible", content: "IE=edge" |
||||||
|
meta name: "viewport", content: "width=device-width, initial-scale=1" |
||||||
|
|
||||||
|
title(title) |
||||||
|
link href: "http://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css", rel: "stylesheet" |
||||||
|
link href: "http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css", rel: "stylesheet" |
||||||
|
link href: "http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css", rel: "stylesheet" |
||||||
|
} |
||||||
|
|
||||||
|
body { |
||||||
|
div(class:'navbar navbar-inverse navbar-fixed-top', role:'navigation') { |
||||||
|
div(class:'container') { |
||||||
|
div(class:'navbar-header') { |
||||||
|
button(type:'button', class:'navbar-toggle', 'data-toggle':'collapse', 'data-target':'navbar-collaspe') { |
||||||
|
span(class:'sr-only', 'Toggle navigation') |
||||||
|
span(class:'icon-bar'){} |
||||||
|
span(class:'icon-bar'){} |
||||||
|
span(class:'icon-bar'){} |
||||||
|
} |
||||||
|
a(class:'navbar-brand',href:'#', 'Binary compatibility report') |
||||||
|
} |
||||||
|
div(class:'navbar-collapse collapse') { |
||||||
|
ul(class:"nav navbar-nav") { |
||||||
|
li(class: 'dropdown') { |
||||||
|
a(id: 'severityDropdown', href: '#', class: 'dropdown-toggle', 'data-toggle': 'dropdown', 'Severity <span class="caret"></span>') |
||||||
|
ul(class: "dropdown-menu dropdown-severity", role: "menu") { |
||||||
|
li(role: 'presentation', class: 'active') { |
||||||
|
a(role: 'menuitem', tabindex: '-1', href: '#', 'All levels') |
||||||
|
} |
||||||
|
li(role: 'presentation') { a(role: 'menuitem', tabindex: '-1', href: '#', 'Error') } |
||||||
|
li(role: 'presentation') { a(role: 'menuitem', tabindex: '-1', href: '#', 'Warning') } |
||||||
|
li(role: 'presentation') { a(role: 'menuitem', tabindex: '-1', href: '#', 'Info') } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
div(class: 'container') { |
||||||
|
div(class:'jumbotron') { |
||||||
|
div(class:'container') { |
||||||
|
div(class: 'page-header') { |
||||||
|
h1 'Binary compatibility' |
||||||
|
p "Comparing ${archive} to reference ${baseline}" |
||||||
|
p { |
||||||
|
yield "Be warned that this report is not perfect and depends on what " |
||||||
|
a(href: 'https://github.com/siom79/japicmp', 'JApicmp') |
||||||
|
yield " is capable to detect." |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
violations.each { fqcn, classViolations -> |
||||||
|
def errors = classViolations.keySet() |
||||||
|
def severities = errors.collect { "severity-${it}" } |
||||||
|
div(class: "panel panel-default ${severities.join(' ')}") { |
||||||
|
div(class: "panel-heading") { |
||||||
|
h3(class: 'panel-title', "Class $fqcn") |
||||||
|
} |
||||||
|
div(class: 'panel-body') { |
||||||
|
table(class: "table table-striped table-bordered") { |
||||||
|
tbody { |
||||||
|
classViolations.each { err, list -> |
||||||
|
list.each { item -> |
||||||
|
tr(class: "bincompat-error severity-${err}") { |
||||||
|
td { |
||||||
|
h4 { |
||||||
|
span(class: "label label-${severityMapping[err]}", err.capitalize()) |
||||||
|
} |
||||||
|
} |
||||||
|
td { span(item) } |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
script(src: "http://code.jquery.com/jquery-1.11.0.min.js") {} |
||||||
|
script(src: "http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js") {} |
||||||
|
script { |
||||||
|
yieldUnescaped ''' |
||||||
|
$(document).ready(function () { |
||||||
|
var severity = null; |
||||||
|
doFilter(); |
||||||
|
function doFilter() { |
||||||
|
var severityClass = "severity-" + severity; |
||||||
|
$('.panel').hide(); |
||||||
|
$('.bincompat-error').hide(); |
||||||
|
$('.bincompat-error').filter(function () { |
||||||
|
return (severity==null || $(this).hasClass(severityClass)); |
||||||
|
}).show(); |
||||||
|
$('.panel').filter(function () { |
||||||
|
return (severity==null || $(this).hasClass(severityClass)); |
||||||
|
}).show(); |
||||||
|
} |
||||||
|
$(".dropdown-severity li a").click(function() { |
||||||
|
severity = $(this).text().toLowerCase(); |
||||||
|
if (severity==="all levels") { |
||||||
|
severity = null; |
||||||
|
} |
||||||
|
doFilter(); |
||||||
|
}); |
||||||
|
});''' |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,91 @@ |
|||||||
|
package com.jayway.jsonpath; |
||||||
|
|
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import static com.jayway.jsonpath.JsonPath.using; |
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
|
public class JsonProviderTest extends BaseTest { |
||||||
|
|
||||||
|
private static final String JSON = |
||||||
|
"[" + |
||||||
|
"{\n" + |
||||||
|
" \"foo\" : \"foo0\",\n" + |
||||||
|
" \"bar\" : 0,\n" + |
||||||
|
" \"baz\" : true,\n" + |
||||||
|
" \"gen\" : {\"prop\" : \"yepp0\"}" + |
||||||
|
"}," + |
||||||
|
"{\n" + |
||||||
|
" \"foo\" : \"foo1\",\n" + |
||||||
|
" \"bar\" : 1,\n" + |
||||||
|
" \"baz\" : true,\n" + |
||||||
|
" \"gen\" : {\"prop\" : \"yepp1\"}" + |
||||||
|
"}," + |
||||||
|
"{\n" + |
||||||
|
" \"foo\" : \"foo2\",\n" + |
||||||
|
" \"bar\" : 2,\n" + |
||||||
|
" \"baz\" : true,\n" + |
||||||
|
" \"gen\" : {\"prop\" : \"yepp2\"}" + |
||||||
|
"}" + |
||||||
|
"]"; |
||||||
|
|
||||||
|
@Test |
||||||
|
public void strings_are_unwrapped() { |
||||||
|
assertThat(using(JACKSON_CONFIGURATION).parse(JSON_DOCUMENT).read("$.string-property", String.class)).isEqualTo("string-value"); |
||||||
|
assertThat(using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$.string-property", String.class)).isEqualTo("string-value"); |
||||||
|
assertThat(using(JSON_SMART_CONFIGURATION).parse(JSON_DOCUMENT).read("$.string-property", String.class)).isEqualTo("string-value"); |
||||||
|
assertThat(using(GSON_CONFIGURATION).parse(JSON_DOCUMENT).read("$.string-property", String.class)).isEqualTo("string-value"); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void integers_are_unwrapped() { |
||||||
|
assertThat(using(JACKSON_CONFIGURATION).parse(JSON_DOCUMENT).read("$.int-max-property", Integer.class)).isEqualTo(Integer.MAX_VALUE); |
||||||
|
assertThat(using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$.int-max-property", Integer.class)).isEqualTo(Integer.MAX_VALUE); |
||||||
|
assertThat(using(JSON_SMART_CONFIGURATION).parse(JSON_DOCUMENT).read("$.int-max-property", Integer.class)).isEqualTo(Integer.MAX_VALUE); |
||||||
|
assertThat(using(GSON_CONFIGURATION).parse(JSON_DOCUMENT).read("$.int-max-property", Integer.class)).isEqualTo(Integer.MAX_VALUE); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void ints_are_unwrapped() { |
||||||
|
assertThat(using(JACKSON_CONFIGURATION).parse(JSON_DOCUMENT).read("$.int-max-property", int.class)).isEqualTo(Integer.MAX_VALUE); |
||||||
|
assertThat(using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$.int-max-property", int.class)).isEqualTo(Integer.MAX_VALUE); |
||||||
|
assertThat(using(JSON_SMART_CONFIGURATION).parse(JSON_DOCUMENT).read("$.int-max-property", int.class)).isEqualTo(Integer.MAX_VALUE); |
||||||
|
assertThat(using(GSON_CONFIGURATION).parse(JSON_DOCUMENT).read("$.int-max-property", int.class)).isEqualTo(Integer.MAX_VALUE); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void list_of_numbers() { |
||||||
|
|
||||||
|
TypeRef<List<Double>> typeRef = new TypeRef<List<Double>>() {}; |
||||||
|
|
||||||
|
assertThat(using(JACKSON_TREE_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[*].display-price", typeRef)).containsExactly(8.95D, 12.99D, 8.99D, 22.99D); |
||||||
|
assertThat(using(JACKSON_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[*].display-price", typeRef)).containsExactly(8.95D, 12.99D, 8.99D, 22.99D); |
||||||
|
assertThat(using(GSON_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[*].display-price", typeRef)).containsExactly(8.95D, 12.99D, 8.99D, 22.99D); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void test_type_ref() throws IOException { |
||||||
|
TypeRef<List<FooBarBaz<Sub>>> typeRef = new TypeRef<List<FooBarBaz<Sub>>>() {}; |
||||||
|
|
||||||
|
assertThat(using(JACKSON_CONFIGURATION).parse(JSON).read("$", typeRef)).extracting("foo").containsExactly("foo0", "foo1", "foo2"); |
||||||
|
assertThat(using(JACKSON_TREE_CONFIGURATION).parse(JSON).read("$", typeRef)).extracting("foo").containsExactly("foo0", "foo1", "foo2"); |
||||||
|
assertThat(using(GSON_CONFIGURATION).parse(JSON).read("$", typeRef)).extracting("foo").containsExactly("foo0", "foo1", "foo2"); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public static class FooBarBaz<T> { |
||||||
|
public T gen; |
||||||
|
public String foo; |
||||||
|
public Long bar; |
||||||
|
public boolean baz; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public static class Sub { |
||||||
|
public String prop; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,69 +0,0 @@ |
|||||||
package com.jayway.jsonpath; |
|
||||||
|
|
||||||
import org.junit.Test; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import static com.jayway.jsonpath.JsonPath.parse; |
|
||||||
import static com.jayway.jsonpath.JsonPath.using; |
|
||||||
import static org.assertj.core.api.Assertions.assertThat; |
|
||||||
|
|
||||||
public class JsonSmartMappingProviderTest { |
|
||||||
|
|
||||||
private static final String JSON = |
|
||||||
"[" + |
|
||||||
"{\n" + |
|
||||||
" \"foo\" : \"foo0\",\n" + |
|
||||||
" \"bar\" : 0,\n" + |
|
||||||
" \"baz\" : true,\n" + |
|
||||||
" \"gen\" : {\"eric\" : \"yepp\"}" + |
|
||||||
"}," + |
|
||||||
"{\n" + |
|
||||||
" \"foo\" : \"foo1\",\n" + |
|
||||||
" \"bar\" : 1,\n" + |
|
||||||
" \"baz\" : true,\n" + |
|
||||||
" \"gen\" : {\"eric\" : \"yepp\"}" + |
|
||||||
"}," + |
|
||||||
"{\n" + |
|
||||||
" \"foo\" : \"foo2\",\n" + |
|
||||||
" \"bar\" : 2,\n" + |
|
||||||
" \"baz\" : true,\n" + |
|
||||||
" \"gen\" : {\"eric\" : \"yepp\"}" + |
|
||||||
"}" + |
|
||||||
"]"; |
|
||||||
|
|
||||||
@Test |
|
||||||
public void class_mapping() { |
|
||||||
|
|
||||||
Object map = Configuration.defaultConfiguration().jsonProvider().createMap(); |
|
||||||
Configuration.defaultConfiguration().jsonProvider().setProperty(map, "eric", "eric-val"); |
|
||||||
|
|
||||||
|
|
||||||
Gen gen = parse(map).read("$", Gen.class); |
|
||||||
|
|
||||||
assertThat(gen.eric).isEqualTo("eric-val"); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
@Test(expected = UnsupportedOperationException.class) |
|
||||||
public void test_type_ref() throws IOException { |
|
||||||
|
|
||||||
TypeRef<List<FooBarBaz>> typeRef = new TypeRef<List<FooBarBaz>>() {}; |
|
||||||
|
|
||||||
List gen = parse(JSON).read("$", typeRef); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public static class FooBarBaz { |
|
||||||
public Gen gen; |
|
||||||
public String foo; |
|
||||||
public Long bar; |
|
||||||
public boolean baz; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public static class Gen { |
|
||||||
public String eric; |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue