Kalle Stenflo
10 years ago
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