//
// Copyright © 2014, David Tesler (https://github.com/protobufel)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
package com.github.protobufel.grammar;
import static com.github.protobufel.grammar.Misc.getFileDescriptorProtos;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer;
import org.assertj.core.api.JUnitSoftAssertions;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.protobufel.grammar.ErrorListeners.IBaseProtoErrorListener;
import com.github.protobufel.grammar.ErrorListeners.LogProtoErrorListener;
import com.github.protobufel.grammar.Misc.FieldTypeRefsMode;
import com.github.protobufel.grammar.Misc.FileDescriptorByNameComparator;
import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
import difflib.DiffRow;
import difflib.DiffRow.Tag;
import difflib.DiffRowGenerator;
import difflib.DiffUtils;
import difflib.Patch;
import difflib.PatchFailedException;
@RunWith(JUnit4.class)
public class DiffWithOriginalsTest {
@SuppressWarnings("unused")
private static final Logger log = LoggerFactory.getLogger(DiffWithOriginalsTest.class);
public static final int MAX_FIELD_NUMBER = 536870912;
private static final String PROTOBUF_ORIGINAL_SUBDIR = "protobuf-original/";
private static final Pattern ALL_PROTOS_PATTERN = Pattern.compile(".*\\.proto");
private File baseDir;
private final Pattern filePattern = ALL_PROTOS_PATTERN;
// private List<String> files;
@Mock
private IBaseProtoErrorListener mockErrorListener;
private LogProtoErrorListener errorListener;
private ProtoFiles.Builder filesBuilder;
private List<FileDescriptorProto> protocFdProtos;
public final ExpectedException expected = ExpectedException.none();
public final JUnitSoftAssertions softly = new JUnitSoftAssertions();
@Rule
public final TestRule chain = RuleChain.outerRule(expected).around(new MockitoJUnitRule(this))
.around(softly);
@SuppressWarnings("null")
@Before
public void setUp() throws Exception {
// given
errorListener = new LogProtoErrorListener(mockErrorListener).setLogger(getClass());
filesBuilder = ProtoFiles.newBuilder(errorListener).setProtocCompatible(false);
baseDir = new File(getClass().getResource(PROTOBUF_ORIGINAL_SUBDIR).toURI());
protocFdProtos =
getFileDescriptorProtos(filePattern, false, FieldTypeRefsMode.AS_IS,
PROTOBUF_ORIGINAL_SUBDIR + "FileDescriptorSet", getClass());
}
@After
public void tearDown() throws Exception {}
@Test
public void testDiffs2() throws URISyntaxException, IOException, PatchFailedException {
// given
final List<FileDescriptorProto> expectedProtoList = protocFdProtos;
// when
final List<FileDescriptorProto> actualProtoList =
filesBuilder.setCustomOptionsAsExtensions(false).setProtocCompatible(false)
.addFilesByGlob(baseDir, "**/*.proto").buildProtos(false);
// then
// no errors logged!
verify(mockErrorListener, never()).validationError(anyInt(), anyInt(), anyString(),
any(RuntimeException.class));
verify(mockErrorListener, never()).syntaxError(any(Recognizer.class), any(), anyInt(),
anyInt(), anyString(), any(RecognitionException.class));
softly.assertThat(actualProtoList).as("check actualProtoList is not null").isNotNull();
softly.assertThat(actualProtoList).as("check actualProtoList without nulls")
.doesNotContainNull();
softly.assertThat(actualProtoList).as("check actualProtoList has no duplicates")
.extracting("package", "name").doesNotHaveDuplicates();
softly.assertThat(actualProtoList).as("check actualProtoList size")
.hasSameSizeAs(expectedProtoList);
softly.assertThat(actualProtoList).as("check all protos' by name and package")
.usingElementComparatorOnFields("package", "name")
.containsOnlyElementsOf(expectedProtoList);
final List<FileDescriptorProto> sortedActualFds =
FileDescriptorByNameComparator.of().immutableSortedCopy(actualProtoList);
final List<FileDescriptorProto> sortedExpectedFds =
FileDescriptorByNameComparator.of().immutableSortedCopy(expectedProtoList);
final List<String> actualLines = toLines(sortedActualFds);
final List<String> expectedLines = toLines(sortedExpectedFds);
final Patch<String> patch = DiffUtils.diff(actualLines, expectedLines);
// log.debug("patch text {}", patch.getDeltas());
final DiffRowGenerator diffBuilder =
new DiffRowGenerator.Builder().ignoreWhiteSpaces(false).ignoreBlankLines(false)
.columnWidth(132).showInlineDiffs(false).build();
final List<DiffRow> diffRows = diffBuilder.generateDiffRows(actualLines, expectedLines);
final List<DiffRow> diffList = new ArrayList<>();
for (final DiffRow diffRow : diffRows) {
if (diffRow.getTag() != Tag.EQUAL) {
diffList.add(diffRow);
}
}
log.debug("diff rows {}", diffList);
softly.assertThat(patch.applyTo(actualLines)).as("check the patched")
.containsExactlyElementsOf(expectedLines);
softly.assertThat(patch.restore(expectedLines)).as("check the reverse patched")
.containsExactlyElementsOf(actualLines);
// final StringBuilder sb = new StringBuilder();
//
// for (final Delta<FileDescriptorProto> delta : patch.getDeltas()) {
// sb.append(delta);
// }
//
// log.debug("patch text {}", sb.toString());
}
private <T> List<String> toLines(final List<T> list) {
final List<String> lines = new ArrayList<String>();
for (final T el : list) {
lines.addAll(toLines(el.toString()));
}
return lines;
}
private List<String> toLines(final String text) {
return Arrays.asList(text.split("\\r?\\n"));
}
}