Add Java API for change edits and use it in tests

For some reason, a Java API for change edits didn't exist previously
even though a detailed REST API has been available. Because of that,
tests needed to use internal classes when they interacted with change
edits. Using internal classes is fragile and impedes refactorings.
That's why we should avoid it.

If possible, the structure and behavior of the tests is kept. Some of
them might and should be improved but that's beyond the scope of this
change. Some of the tests are adapted a bit because the internal
classes allow change edits to be created for previous patch sets
which isn't possible when using the REST API (and hence the Java API).

As modifications to the mentioned internal classes are necessary to
properly implement the 'Apply fix' feature of robot comments, it is
crucial that none of the tests use the internal classes directly.
In addition, the tests which will be added for the 'Apply fix' feature
will also need to modify and query change edits, which will be much
easier with the Java API.

Change-Id: I6b455541d1bc1b7a05b5f0507911181b0451829a
This commit is contained in:
Alice Kober-Sotzek
2017-01-16 12:07:13 +01:00
parent 2a82c08023
commit 5dd17b647e
18 changed files with 1454 additions and 544 deletions

View File

@@ -0,0 +1,66 @@
// Copyright (C) 2017 The Android Open Source Project
//
// 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 com.google.gerrit.extensions.common;
import static com.google.common.truth.Truth.assertAbout;
import com.google.common.truth.FailureStrategy;
import com.google.common.truth.StringSubject;
import com.google.common.truth.Subject;
import com.google.common.truth.SubjectFactory;
import com.google.common.truth.Truth;
import com.google.gerrit.truth.ListSubject;
public class CommitInfoSubject extends Subject<CommitInfoSubject, CommitInfo> {
private static final SubjectFactory<CommitInfoSubject, CommitInfo>
COMMIT_INFO_SUBJECT_FACTORY =
new SubjectFactory<CommitInfoSubject, CommitInfo>() {
@Override
public CommitInfoSubject getSubject(FailureStrategy failureStrategy,
CommitInfo commitInfo) {
return new CommitInfoSubject(failureStrategy, commitInfo);
}
};
public static CommitInfoSubject assertThat(CommitInfo commitInfo) {
return assertAbout(COMMIT_INFO_SUBJECT_FACTORY)
.that(commitInfo);
}
private CommitInfoSubject(FailureStrategy failureStrategy,
CommitInfo commitInfo) {
super(failureStrategy, commitInfo);
}
public StringSubject commit() {
isNotNull();
CommitInfo commitInfo = actual();
return Truth.assertThat(commitInfo.commit).named("commit");
}
public ListSubject<CommitInfoSubject, CommitInfo> parents() {
isNotNull();
CommitInfo commitInfo = actual();
return ListSubject.assertThat(commitInfo.parents,
CommitInfoSubject::assertThat).named("parents");
}
public GitPersonSubject committer() {
isNotNull();
CommitInfo commitInfo = actual();
return GitPersonSubject.assertThat(commitInfo.committer).named("committer");
}
}

View File

@@ -0,0 +1,67 @@
// Copyright (C) 2017 The Android Open Source Project
//
// 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 com.google.gerrit.extensions.common;
import static com.google.common.truth.Truth.assertAbout;
import com.google.common.truth.FailureStrategy;
import com.google.common.truth.StringSubject;
import com.google.common.truth.Subject;
import com.google.common.truth.SubjectFactory;
import com.google.common.truth.Truth;
import com.google.gerrit.truth.OptionalSubject;
import java.util.Optional;
public class EditInfoSubject extends Subject<EditInfoSubject, EditInfo> {
private static final SubjectFactory<EditInfoSubject, EditInfo>
EDIT_INFO_SUBJECT_FACTORY =
new SubjectFactory<EditInfoSubject, EditInfo>() {
@Override
public EditInfoSubject getSubject(FailureStrategy failureStrategy,
EditInfo editInfo) {
return new EditInfoSubject(failureStrategy, editInfo);
}
};
public static EditInfoSubject assertThat(EditInfo editInfo) {
return assertAbout(EDIT_INFO_SUBJECT_FACTORY)
.that(editInfo);
}
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public static OptionalSubject<EditInfoSubject, EditInfo> assertThat(
Optional<EditInfo> editInfoOptional) {
return OptionalSubject.assertThat(editInfoOptional,
EditInfoSubject::assertThat);
}
private EditInfoSubject(FailureStrategy failureStrategy, EditInfo editInfo) {
super(failureStrategy, editInfo);
}
public CommitInfoSubject commit() {
isNotNull();
EditInfo editInfo = actual();
return CommitInfoSubject.assertThat(editInfo.commit).named("commit");
}
public StringSubject baseRevision() {
isNotNull();
EditInfo editInfo = actual();
return Truth.assertThat(editInfo.baseRevision).named("baseRevision");
}
}

View File

@@ -0,0 +1,54 @@
// Copyright (C) 2017 The Android Open Source Project
//
// 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 com.google.gerrit.extensions.common;
import static com.google.common.truth.Truth.assertAbout;
import com.google.common.truth.ComparableSubject;
import com.google.common.truth.FailureStrategy;
import com.google.common.truth.Subject;
import com.google.common.truth.SubjectFactory;
import com.google.common.truth.Truth;
import java.sql.Timestamp;
public class GitPersonSubject extends Subject<GitPersonSubject, GitPerson> {
private static final SubjectFactory<GitPersonSubject, GitPerson>
GIT_PERSON_SUBJECT_FACTORY =
new SubjectFactory<GitPersonSubject, GitPerson>() {
@Override
public GitPersonSubject getSubject(FailureStrategy failureStrategy,
GitPerson gitPerson) {
return new GitPersonSubject(failureStrategy, gitPerson);
}
};
public static GitPersonSubject assertThat(GitPerson gitPerson) {
return assertAbout(GIT_PERSON_SUBJECT_FACTORY)
.that(gitPerson);
}
private GitPersonSubject(FailureStrategy failureStrategy,
GitPerson gitPerson) {
super(failureStrategy, gitPerson);
}
public ComparableSubject<?, Timestamp> creationDate() {
isNotNull();
GitPerson gitPerson = actual();
return Truth.assertThat(gitPerson.date).named("creationDate");
}
}

View File

@@ -0,0 +1,73 @@
// Copyright (C) 2017 The Android Open Source Project
//
// 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 com.google.gerrit.extensions.restapi;
import static com.google.common.truth.Truth.assertAbout;
import com.google.common.truth.FailureStrategy;
import com.google.common.truth.PrimitiveByteArraySubject;
import com.google.common.truth.Subject;
import com.google.common.truth.SubjectFactory;
import com.google.common.truth.Truth;
import com.google.gerrit.truth.OptionalSubject;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Optional;
public class BinaryResultSubject
extends Subject<BinaryResultSubject, BinaryResult> {
private static final SubjectFactory<BinaryResultSubject, BinaryResult>
BINARY_RESULT_SUBJECT_FACTORY =
new SubjectFactory<BinaryResultSubject, BinaryResult>() {
@Override
public BinaryResultSubject getSubject(FailureStrategy failureStrategy,
BinaryResult binaryResult) {
return new BinaryResultSubject(failureStrategy,
binaryResult);
}
};
public static BinaryResultSubject assertThat(BinaryResult binaryResult) {
return assertAbout(BINARY_RESULT_SUBJECT_FACTORY)
.that(binaryResult);
}
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public static OptionalSubject<BinaryResultSubject, BinaryResult> assertThat(
Optional<BinaryResult> binaryResultOptional) {
return OptionalSubject.assertThat(binaryResultOptional,
BinaryResultSubject::assertThat);
}
private BinaryResultSubject(FailureStrategy failureStrategy,
BinaryResult binaryResult) {
super(failureStrategy, binaryResult);
}
public PrimitiveByteArraySubject bytes() throws IOException {
isNotNull();
// We shouldn't close the BinaryResult within this method as it might still
// be used afterwards. Besides, closing it doesn't have an effect for most
// implementations of a BinaryResult.
@SuppressWarnings("resource")
BinaryResult binaryResult = actual();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
binaryResult.writeTo(byteArrayOutputStream);
byte[] bytes = byteArrayOutputStream.toByteArray();
return Truth.assertThat(bytes);
}
}

View File

@@ -0,0 +1,105 @@
// Copyright (C) 2017 The Android Open Source Project
//
// 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 com.google.gerrit.truth;
import static com.google.common.truth.Truth.assertAbout;
import com.google.common.truth.DefaultSubject;
import com.google.common.truth.FailureStrategy;
import com.google.common.truth.Subject;
import com.google.common.truth.SubjectFactory;
import com.google.common.truth.Truth;
import java.util.Optional;
import java.util.function.Function;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public class OptionalSubject<S extends Subject<S, ? super T>, T>
extends Subject<OptionalSubject<S, T>, Optional<T>> {
private final Function<? super T, ? extends S> valueAssertThatFunction;
public static <S extends Subject<S, ? super T>, T> OptionalSubject<S, T>
assertThat(Optional<T> optional,
Function<? super T, ? extends S> elementAssertThatFunction) {
OptionalSubjectFactory<S, T> optionalSubjectFactory =
new OptionalSubjectFactory<>(elementAssertThatFunction);
return assertAbout(optionalSubjectFactory).that(optional);
}
public static OptionalSubject<DefaultSubject, ?> assertThat(
Optional<?> optional) {
// Unfortunately, we need to cast to DefaultSubject as Truth.assertThat()
// only returns Subject<DefaultSubject, Object>. There shouldn't be a way
// for that method not to return a DefaultSubject because the generic type
// definitions of a Subject are quite strict.
Function<Object, DefaultSubject> valueAssertThatFunction =
value -> (DefaultSubject) Truth.assertThat(value);
return assertThat(optional, valueAssertThatFunction);
}
private OptionalSubject(FailureStrategy failureStrategy, Optional<T> optional,
Function<? super T, ? extends S> valueAssertThatFunction) {
super(failureStrategy, optional);
this.valueAssertThatFunction = valueAssertThatFunction;
}
public void isPresent() {
isNotNull();
Optional<T> optional = actual();
if (!optional.isPresent()) {
fail("has a value");
}
}
public void isAbsent() {
isNotNull();
Optional<T> optional = actual();
if (optional.isPresent()) {
fail("does not have a value");
}
}
public void isEmpty() {
isAbsent();
}
@SuppressWarnings("OptionalGetWithoutIsPresent")
public S value() {
isNotNull();
isPresent();
Optional<T> optional = actual();
return valueAssertThatFunction.apply(optional.get());
}
private static class OptionalSubjectFactory<S extends Subject<S, ? super T>,
T> extends SubjectFactory<OptionalSubject<S, T>, Optional<T>> {
private Function<? super T, ? extends S> valueAssertThatFunction;
OptionalSubjectFactory(
Function<? super T, ? extends S> valueAssertThatFunction) {
this.valueAssertThatFunction = valueAssertThatFunction;
}
@Override
public OptionalSubject<S, T> getSubject(FailureStrategy failureStrategy,
Optional<T> optional) {
return new OptionalSubject<>(failureStrategy, optional,
valueAssertThatFunction);
}
}
}