
org.gradle.tooling.internal.adapter.ProtocolToModelAdapterTest.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* Copyright 2012 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.
*/
package org.gradle.tooling.internal.adapter
import org.gradle.internal.serialize.Message
import org.gradle.tooling.model.DomainObjectSet
import org.gradle.tooling.model.UnsupportedMethodException
import org.gradle.util.Matchers
import spock.lang.Specification
import java.lang.reflect.InvocationHandler
import java.nio.channels.ByteChannel
import java.nio.channels.Channel
class ProtocolToModelAdapterTest extends Specification {
final ProtocolToModelAdapter adapter = new ProtocolToModelAdapter()
def mapsNullToNull() {
expect:
adapter.adapt(TestModel.class, null) == null
}
def createsProxyAdapterForProtocolModel() {
TestProtocolModel protocolModel = Mock()
expect:
adapter.adapt(TestModel.class, protocolModel) instanceof TestModel
}
def proxiesAreEqualWhenTargetProtocolObjectsAreEqual() {
TestProtocolModel protocolModel1 = Mock()
TestProtocolModel protocolModel2 = Mock()
def model = adapter.adapt(TestModel.class, protocolModel1)
def equal = adapter.adapt(TestModel.class, protocolModel1)
def different = adapter.adapt(TestModel.class, protocolModel2)
expect:
Matchers.strictlyEquals(model, equal)
model != different
}
def methodInvocationOnModelDelegatesToTheProtocolModelObject() {
TestProtocolModel protocolModel = Mock()
_ * protocolModel.getName() >> 'name'
expect:
def model = adapter.adapt(TestModel.class, protocolModel)
model.name == 'name'
}
def createsProxyAdapterForMethodReturnValue() {
TestProtocolModel protocolModel = Mock()
TestProtocolProject protocolProject = Mock()
_ * protocolModel.getProject() >> protocolProject
_ * protocolProject.getName() >> 'name'
expect:
def model = adapter.adapt(TestModel.class, protocolModel)
model.project instanceof TestProject
model.project.name == 'name'
}
def doesNotAdaptNullReturnValue() {
TestProtocolModel protocolModel = Mock()
_ * protocolModel.getProject() >> null
expect:
def model = adapter.adapt(TestModel.class, protocolModel)
model.project == null
}
def adaptsIterableToDomainObjectSet() {
TestProtocolModel protocolModel = Mock()
TestProtocolProject protocolProject = Mock()
_ * protocolModel.getChildren() >> [protocolProject]
_ * protocolProject.getName() >> 'name'
expect:
def model = adapter.adapt(TestModel.class, protocolModel)
model.children.size() == 1
model.children[0] instanceof TestProject
model.children[0].name == 'name'
}
def adaptsIterableToCollectionType() {
TestProtocolModel protocolModel = Mock()
TestProtocolProject protocolProject = Mock()
_ * protocolModel.getChildList() >> [protocolProject]
_ * protocolProject.getName() >> 'name'
expect:
def model = adapter.adapt(TestModel.class, protocolModel)
model.childList.size() == 1
model.childList[0] instanceof TestProject
model.childList[0].name == 'name'
}
def adaptsMapElements() {
TestProtocolModel protocolModel = Mock()
TestProtocolProject protocolProject = Mock()
_ * protocolModel.project >> protocolProject
_ * protocolModel.getChildMap() >> Collections.singletonMap(protocolProject, protocolProject)
_ * protocolProject.getName() >> 'name'
expect:
def model = adapter.adapt(TestModel.class, protocolModel)
model.childMap.size() == 1
model.childMap[model.project] == model.project
}
def adaptsEnum() {
TestProtocolModel protocolModel = Mock()
_ * protocolModel.getTestEnum() >> TestEnum.FIRST
expect:
TestModel model = adapter.adapt(TestModel.class, protocolModel)
model.testEnum == TestEnum.FIRST
}
def adaptsStringToEnum() {
TestProtocolModel protocolModel = Mock()
_ * protocolModel.getTestEnum() >> "SECOND"
expect:
TestModel model = adapter.adapt(TestModel.class, protocolModel)
model.testEnum == TestEnum.SECOND
}
def cantAdaptInvalidEnumLiteral() {
setup:
TestProtocolModel protocolModel = Mock()
_ * protocolModel.getTestEnum() >> "NONEXISTING"
when:
TestModel model = adapter.adapt(TestModel.class, protocolModel)
model.getTestEnum()
then:
thrown(IllegalArgumentException)
}
def cachesPropertyValues() {
TestProtocolModel protocolModel = Mock()
TestProtocolProject protocolProject = Mock()
_ * protocolModel.getProject() >> protocolProject
_ * protocolModel.getChildren() >> [protocolProject]
_ * protocolProject.getName() >> 'name'
expect:
def model = adapter.adapt(TestModel.class, protocolModel)
model.project.is(model.project)
model.children.is(model.children)
}
def "reuses views for each object in backing graph"() {
TestProtocolModel protocolModel = Mock()
TestProtocolProject protocolProject = Mock()
_ * protocolModel.getProject() >> protocolProject
_ * protocolModel.getChildren() >> [protocolProject]
_ * protocolModel.find("name") >> protocolProject
expect:
def model = adapter.adapt(TestModel.class, protocolModel)
def project = model.project
model.project.is(project)
model.children[0].is(project)
model.find("name").is(project)
}
def "can have path to root view"() {
TestProtocolProjectTree parent = Mock()
TestProtocolProjectTree child = Mock()
parent.child >> child
child.parent >> parent
expect:
def model = adapter.adapt(TestProjectTree.class, parent)
model.child.parent.is(model)
}
def "does not reuse views for different objects that are equal"() {
TestProtocolModel protocolModel = Mock()
TestProtocolProject project1 = new TestProtocolProjectWithEquality()
TestProtocolProject project2 = new TestProtocolProjectWithEquality()
_ * protocolModel.getProject() >> project1
_ * protocolModel.getChildList() >> [project2, project1]
assert project1 == project2
expect:
def model = adapter.adapt(TestModel.class, protocolModel)
!model.childList[0].is(model.project)
model.childList[1].is(model.project)
}
def "does not reuse views from different graphs"() {
TestProtocolModel protocolModel1 = Mock()
TestProtocolModel protocolModel2 = Mock()
TestProtocolProject protocolProject = Mock()
_ * protocolModel1.getProject() >> protocolProject
_ * protocolModel2.getProject() >> protocolProject
expect:
def model1 = adapter.adapt(TestModel.class, protocolModel1)
def model2 = adapter.adapt(TestModel.class, protocolModel2)
!model1.is(model2)
!model1.project.is(model2.project)
}
def "can create converter that reuses views for multiple converted objects"() {
TestProtocolModel protocolModel1 = Mock()
TestProtocolModel protocolModel2 = Mock()
TestProtocolProject protocolProject = Mock()
_ * protocolModel1.getProject() >> protocolProject
_ * protocolModel2.getProject() >> protocolProject
expect:
def converter = adapter.newGraph()
def model1 = converter.adapt(TestModel.class, protocolModel1)
def model2 = converter.adapt(TestModel.class, protocolModel2)
!model1.is(model2)
model1.project.is(model2.project)
def otherModel1 = converter.adapt(TestModel.class, protocolModel1)
model1.is(otherModel1)
}
def "does not reuse views with different mix ins"() {
TestProtocolModel protocolModel = Mock()
TestProtocolProject protocolProject = Mock()
_ * protocolModel.getProject() >> protocolProject
expect:
def converter = adapter.newGraph()
def model1 = converter.builder(TestModel.class).mixInTo(TestModel, ConfigMixin).build(protocolModel)
def model2 = converter.adapt(TestModel.class, protocolModel)
!model1.is(model2)
def model3 = converter.builder(TestModel.class).build(protocolModel)
model3.is(model2)
def model4 = converter.builder(TestModel.class).mixInTo(TestModel, ConfigMixin).build(protocolModel)
model4.is(model1)
def model5 = converter.builder(TestModel.class).mixInTo(TestProject, "instance").build(protocolModel)
!model5.is(model1)
!model5.is(model2)
def model6 = converter.builder(TestModel.class).mixInTo(TestProject, "instance").build(protocolModel)
model6.is(model5)
}
def "does not reuse views when some view reachable has different mix ins"() {
TestProtocolModel protocolModel = Mock()
TestProtocolProject protocolProject = Mock()
_ * protocolModel.getProject() >> protocolProject
expect:
def converter = adapter.newGraph()
def model1 = converter.builder(TestModel.class).mixInTo(TestProject, ProjectMixin).build(protocolModel)
def model2 = converter.adapt(TestModel.class, protocolModel)
!model2.is(model1)
!model1.project.is(model2.project)
def model3 = converter.builder(TestModel.class).build(protocolModel)
model3.is(model2)
def model4 = converter.builder(TestModel.class).mixInTo(TestProject, ProjectMixin).build(protocolModel)
model4.is(model1)
def model5 = converter.builder(TestModel.class).mixInTo(TestProject, "instance").build(protocolModel)
!model5.is(model1)
!model5.project.is(model1.project)
!model5.is(model2)
!model5.project.is(model2.project)
def model6 = converter.builder(TestModel.class).mixInTo(TestProject, "instance").build(protocolModel)
model6.is(model5)
}
def "reuses reachable views when they have the same mix ins"() {
TestProtocolModel protocolModel = Mock()
TestProtocolModel protocolModel2 = Mock()
TestProtocolProject protocolProject = Mock()
_ * protocolModel.getProject() >> protocolProject
_ * protocolModel2.getProject() >> protocolProject
expect:
def converter = adapter.newGraph()
def model1 = converter.builder(TestModel.class).mixInTo(TestModel, ConfigMixin).build(protocolModel)
def model2 = converter.adapt(TestModel.class, protocolModel)
!model2.is(model1)
model2.project.is(model1.project)
def model3 = converter.builder(TestModel.class).mixInTo(TestModel, "thing").build(protocolModel2)
!model3.is(model1)
model3.project.is(model1.project)
}
def "ignores mix ins that are not relevant for view type"() {
TestProtocolModel protocolModel = Mock()
TestProtocolProject protocolProject = Mock()
_ * protocolModel.getProject() >> protocolProject
expect:
def converter = adapter.newGraph()
def model1 = converter.builder(TestModel.class).mixInTo(Long, ConfigMixin).mixInTo(Runnable, "instance").build(protocolModel)
def model2 = converter.builder(TestModel.class).mixInTo(Runnable, "instance").build(protocolModel)
model2.is(model1)
def model3 = converter.builder(TestModel.class).build(protocolModel)
model3.is(model1)
}
def "backing object can be viewed as various types"() {
TestProtocolModel protocolModel = Mock()
TestProtocolProject protocolProject = Mock()
_ * protocolModel.getProject() >> protocolProject
_ * protocolModel.getExtendedProject() >> protocolProject
expect:
def model = adapter.adapt(TestModel.class, protocolModel)
model.project.is(model.project)
model.extendedProject
}
def reportsMethodWhichDoesNotExistOnProtocolObject() {
PartialTestProtocolModel protocolModel = Mock()
when:
def model = adapter.adapt(TestModel.class, protocolModel)
model.project
then:
UnsupportedMethodException e = thrown()
e.message.contains "TestModel.getProject()"
}
def propagatesExceptionThrownByProtocolObject() {
TestProtocolModel protocolModel = Mock()
RuntimeException failure = new RuntimeException()
when:
def model = adapter.adapt(TestModel.class, protocolModel)
model.name
then:
protocolModel.name >> { throw failure }
RuntimeException e = thrown()
e == failure
}
def isPropertySupportedMethodReturnsTrueWhenProtocolObjectHasAssociatedProperty() {
TestProtocolModel protocolModel = Mock()
when:
def model = adapter.adapt(TestModel.class, protocolModel)
then:
model.configSupported
}
def isPropertySupportedMethodReturnsFalseWhenProtocolObjectDoesNotHaveAssociatedProperty() {
PartialTestProtocolModel protocolModel = Mock()
when:
def model = adapter.adapt(TestModel.class, protocolModel)
then:
!model.configSupported
}
def safeGetterDelegatesToProtocolObject() {
TestProtocolModel protocolModel = Mock()
given:
protocolModel.config >> "value"
when:
def model = adapter.adapt(TestModel.class, protocolModel)
then:
model.getConfig("default") == "value"
}
def safeGetterDelegatesReturnsDefaultValueWhenProtocolObjectDoesNotHaveAssociatedProperty() {
PartialTestProtocolModel protocolModel = Mock()
when:
def model = adapter.adapt(TestModel.class, protocolModel)
then:
model.getConfig("default") == "default"
}
def safeGetterDelegatesReturnsDefaultValueWhenPropertyValueIsNull() {
TestProtocolModel protocolModel = Mock()
given:
protocolModel.config >> null
when:
def model = adapter.adapt(TestModel.class, protocolModel)
then:
model.getConfig("default") == "default"
}
def "can use safe getter for boolean properties"() {
TestProtocolModel protocolModel = Mock()
when:
def model = adapter.adapt(TestModel.class, protocolModel)
then:
model.isThing(true)
}
def "can mix in methods from another bean class"() {
PartialTestProtocolModel protocolModel = Mock()
given:
protocolModel.name >> 'name'
when:
def model = adapter.builder(TestModel.class).mixInTo(TestModel, ConfigMixin).build(protocolModel)
then:
model.name == "name"
model.project
model.getConfig('default') == "[default]"
}
def "can mix in methods from another bean instance"() {
PartialTestProtocolModel protocolModel = Mock()
TestProject project = Mock()
given:
protocolModel.name >> 'name'
when:
def model = adapter.builder(TestModel.class).mixInTo(TestModel.class, new FixedMixin(project: project)).build(protocolModel)
then:
model.project == project
model.getConfig('default') == "[default]"
}
def "getter on mix in can accept the view as a parameter"() {
PartialTestProtocolModel protocolModel = Mock()
TestProject project = Mock()
given:
protocolModel.name >> 'name'
project.name >> 'name'
when:
def model = adapter.builder(TestModel.class).mixInTo(TestModel.class, new FixedMixin(project: project)).build(protocolModel)
then:
model.project.name == "name"
model.projectName == "[name]"
}
def "adapts values returned from mix in beans"() {
PartialTestProtocolModel protocolModel = Mock()
given:
protocolModel.name >> 'name'
when:
def model = adapter.builder(TestModel.class).mixInTo(TestModel, ConfigMixin).build(protocolModel)
then:
model.project != null
}
def "delegates to type provider to determine type to wrap an object in"() {
def typeProvider = Mock(TargetTypeProvider)
def adapter = new ProtocolToModelAdapter(typeProvider)
def sourceObject = new Object()
given:
_ * typeProvider.getTargetType(Channel, sourceObject) >> ByteChannel
when:
def result = adapter.adapt(Channel.class, sourceObject)
then:
result instanceof ByteChannel
}
def "view object can be serialized"() {
def protocolModel = new TestModelImpl()
given:
def model = adapter.adapt(TestModel.class, protocolModel)
def copiedModel = serialize(model)
expect:
copiedModel instanceof TestModel
copiedModel != model
copiedModel.name == "model"
copiedModel.project.name == "name"
}
def "view identity is retained when serialized"() {
def protocolModel = new TestModelImpl()
given:
def model = adapter.adapt(TestModel.class, protocolModel)
def copy = serialize([model, model.project, model.childList])
expect:
def copiedModel = copy[0]
def copiedProject = copy[1]
def projectList = copy[2]
copiedProject.is(copiedModel.project)
projectList[0].is(copiedModel.project)
}
def "view object with mix-in class can be serialized"() {
def protocolModel = new TestModelImpl()
given:
def model = adapter.builder(TestModel.class).mixInTo(TestModel, ConfigMixin).build(protocolModel)
def copiedModel = serialize(model)
expect:
copiedModel instanceof TestModel
copiedModel != model
copiedModel.name == "model"
copiedModel.getConfig("thing") == "[thing]"
}
def "view object with mix-in can be serialized"() {
def protocolModel = new TestModelImpl()
given:
def model = adapter.builder(TestModel.class).mixInTo(TestModel, new FixedMixin()).build(protocolModel)
def copiedModel = serialize(model)
expect:
copiedModel instanceof TestModel
copiedModel != model
copiedModel.name == "model"
copiedModel.getConfig("thing") == "[thing]"
}
def serialize(Object model) {
def serialized = new ByteArrayOutputStream()
Message.send(model, serialized)
return Message.receive(new ByteArrayInputStream(serialized.toByteArray()), getClass().classLoader)
}
def "unpacks source object from view"() {
def source = new Object()
given:
def view = adapter.adapt(TestProject.class, source)
expect:
adapter.unpack(view).is(source)
}
def "fails when source object is not a view object"() {
when:
adapter.unpack("not a view")
then:
thrown(IllegalArgumentException)
when:
adapter.unpack(java.lang.reflect.Proxy.newProxyInstance(getClass().classLoader, [Runnable] as Class[], Stub(InvocationHandler)))
then:
thrown(IllegalArgumentException)
}
}
interface TestModel {
String getName()
TestProject getProject()
String getProjectName()
TestExtendedProject getExtendedProject()
boolean isConfigSupported()
String getConfig(String defaultValue)
Boolean isThing(Boolean defaultValue)
TestProject find(String name)
DomainObjectSet extends TestProject> getChildren()
List getChildList()
Map getChildMap()
TestEnum getTestEnum()
}
interface TestProject {
String getName()
}
interface TestExtendedProject extends TestProject {
}
interface TestProjectTree extends TestProject {
TestProjectTree getParent()
TestProjectTree getChild()
}
interface TestProtocolModel {
String getName()
TestProtocolProject getProject()
TestProtocolProject getExtendedProject()
TestProtocolProject find(String name)
Iterable extends TestProtocolProject> getChildren()
Iterable extends TestProtocolProject> getChildList()
Map getChildMap()
String getConfig();
Object getTestEnum()
}
interface PartialTestProtocolModel {
String getName()
}
interface TestProtocolProject {
String getName()
}
interface TestProtocolProjectTree {
String getName()
TestProtocolProjectTree getParent()
TestProtocolProjectTree getChild()
}
enum TestEnum {
FIRST, SECOND
}
class TestModelImpl implements Serializable {
String name = "model"
TestProtocolProjectImpl project = new TestProtocolProjectImpl()
List childList = [project]
}
class TestProtocolProjectImpl implements Serializable {
String name = "name"
}
class TestProtocolProjectWithEquality implements TestProtocolProject, Serializable {
String name = "name"
@Override
boolean equals(Object obj) {
return obj.name == name
}
@Override
int hashCode() {
return name.hashCode()
}
}
class ConfigMixin {
TestModel model
ConfigMixin(TestModel model) {
this.model = model
}
Object getProject() {
return new Object()
}
String getConfig(String value) {
return "[${model.getConfig(value)}]"
}
String getName() {
return "[${model.name}]"
}
}
class ProjectMixin {
}
class FixedMixin implements Serializable {
TestProject project
String getConfig(String config) {
return "[$config]"
}
String getProjectName(TestModel model) {
return "[$model.project.name]"
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy