Skip to content

Content of file DiagnosticFrequencyMap_Test.java

/*******************************************************************************
 * Copyright (c) 2019 Christian W. Damus and others.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 * Christian W. Damus - initial API and implementation
 ******************************************************************************/
package org.eclipse.emfforms.spi.common.validation;

import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import static org.hamcrest.CoreMatchers.anything;
import static org.hamcrest.CoreMatchers.everyItem;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
import static org.junit.Assume.assumeThat;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Stream;

import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeDiagnosingMatcher;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/**
 * Test cases for the {@link DiagnosticFrequencyMap} type.
 */
@RunWith(Enclosed.class)
@SuppressWarnings("nls")
public class DiagnosticFrequencyMap_Test {

	private final DiagnosticFrequencyMap fixture;

	/**
	 * Initializes me with my fixture.
	 *
	 * @param fixture my fixture
	 */
	DiagnosticFrequencyMap_Test(DiagnosticFrequencyMap fixture) {
		super();

		this.fixture = fixture;
	}

	@RunWith(JUnit4.class)
	public static class Limited extends DiagnosticFrequencyMap_Test {

		/**
		 * Initializes me.
		 */
		public Limited() {
			super(DiagnosticFrequencyMap.limitedTo(5));
		}

		@Test
		public void isEmpty() {
			assertThat("should be empty", fixture().isEmpty(), is(true));
			charStream("abcdefghijklmnop").map(this::error).forEach(fixture()::add);
			assertThat("should not be empty", fixture().isEmpty(), is(false));
		}

		@Test
		public void isFull() {
			charStream("abcd").map(this::error).forEach(fixture()::add);
			assertThat("limited map should not be full", fixture().isFull(), is(false));
			charStream("efghijklmnop").map(this::error).forEach(fixture()::add);
			assertThat("limited map should be full", fixture().isFull(), is(true));
		}

		@Test
		public void size() {
			assertThat(fixture().size(), is(0));
			charStream("abcd").map(this::warning).forEach(fixture()::add);
			assertThat(fixture().size(), is(4));
			charStream("efghijklmnop").map(this::error).forEach(fixture()::add);
			assertThat(fixture().size(), is(5)); // 5 is the limit
		}

		@Test
		public void getDiscardedSeverity() {
			// Initial conditions
			assertThat(fixture().getDiscardedSeverity(), is(Diagnostic.OK));

			charStream("abcde").map(this::info).forEach(fixture()::add);
			assertThat("nothing should be discarded, yet", fixture().getDiscardedSeverity(), is(Diagnostic.OK));

			charStream("fghij").map(this::warning).forEach(fixture()::add);
			assertThat("infos should be discarded", fixture().getDiscardedSeverity(), is(Diagnostic.INFO));

			charStream("klmno").map(this::error).forEach(fixture()::add);
			assertThat("warnings should be discarded", fixture().getDiscardedSeverity(), is(Diagnostic.WARNING));

			charStream("p").map(this::error).forEach(fixture()::add);
			assertThat("an error should have been discarded", fixture().getDiscardedSeverity(), is(Diagnostic.ERROR));
		}

		@Test
		public void iterator() {
			// Initial conditions
			List<Diagnostic> diagnostics = iterate(fixture());
			assertThat(diagnostics, not(hasItem(anything())));

			fixture().addAll(charStream("abcde").map(this::info).collect(toList()));
			diagnostics = iterate(fixture());
			assertThat(diagnostics, everyItem(matches(Diagnostic.INFO, substringOf("abcde"))));

			fixture().addAll(charStream("fghij").map(this::warning).collect(toList()));
			diagnostics = iterate(fixture());
			assertThat(diagnostics, everyItem(matches(Diagnostic.WARNING, substringOf("fghij"))));

			fixture().addAll(charStream("klmno").map(this::error).collect(toList()));
			diagnostics = iterate(fixture());
			assertThat(diagnostics, everyItem(matches(Diagnostic.ERROR, substringOf("klmno"))));

			fixture().add(error("p"));
			diagnostics = iterate(fixture());
			assertThat("should have discarded new error", diagnostics,
				everyItem(matches(Diagnostic.ERROR, substringOf("klmno"))));
		}

		@Test
		public void clear() {
			charStream("abc").map(this::info).forEach(fixture()::add);
			charStream("def").map(this::warning).forEach(fixture()::add);
			charStream("ghi").map(this::error).forEach(fixture()::add);

			fixture().clear();
			assertThat("not empty", fixture().isEmpty(), is(true));
			assertThat("somehow full", fixture().isFull(), is(false));
			assertThat("has size", fixture().size(), is(0));
			assertThat("something discarded from nothing", fixture().getDiscardedSeverity(), is(Diagnostic.OK));
		}

		@Test
		public void appendTo() {
			// Initial conditions
			final List<Diagnostic> diagnostics = new ArrayList<>();
			fixture().appendTo(diagnostics);
			assertThat(diagnostics, not(hasItem(anything())));

			fixture().addAll(charStream("abcde").map(this::info).collect(toList()));
			diagnostics.clear();
			fixture().appendTo(diagnostics);
			assertThat(diagnostics, everyItem(matches(Diagnostic.INFO, substringOf("abcde"))));

			fixture().addAll(charStream("fghij").map(this::warning).collect(toList()));
			diagnostics.clear();
			fixture().appendTo(diagnostics);
			assertThat(diagnostics, everyItem(matches(Diagnostic.WARNING, substringOf("fghij"))));

			fixture().addAll(charStream("klmno").map(this::error).collect(toList()));
			diagnostics.clear();
			fixture().appendTo(diagnostics);
			assertThat(diagnostics, everyItem(matches(Diagnostic.ERROR, substringOf("klmno"))));

			fixture().add(error("p"));
			diagnostics.clear();
			fixture().appendTo(diagnostics);
			assertThat("should have discarded new error", diagnostics,
				everyItem(matches(Diagnostic.ERROR, substringOf("klmno"))));
		}

		@SuppressWarnings("unchecked")
		@Test
		public void addDiagnosticFilter() {
			final Set<String> vowels = charStream("aeiou").collect(toSet());
			final Predicate<Diagnostic> isVowel = d -> vowels.contains(d.getMessage());
			final Predicate<Diagnostic> isProblem = d -> d.getSeverity() > Diagnostic.INFO;

			fixture().addDiagnosticFilter(isVowel);
			fixture().addDiagnosticFilter(isProblem);

			// initial conditions
			assumeThat(fixture().size(), is(0));
			assumeThat(fixture().getDiscardedSeverity(), is(Diagnostic.OK));

			charStream("abcd").map(this::info).forEach(fixture()::add);
			assertThat(fixture().size(), is(0));
			assertThat(fixture().getDiscardedSeverity(), is(Diagnostic.INFO));
			charStream("efghijklmnop").map(this::warning).forEach(fixture()::add);
			assertThat(fixture().size(), is(3));
			assertThat(fixture().getDiscardedSeverity(), is(Diagnostic.WARNING));
			charStream("qrstuvwxyz").map(this::error).forEach(fixture()::add);
			assertThat(fixture().size(), is(4));
			assertThat(fixture().getDiscardedSeverity(), is(Diagnostic.ERROR));

			final List<Diagnostic> collected = iterate(fixture());
			assertThat(collected, hasItems(
				matches(Diagnostic.WARNING, "e"),
				matches(Diagnostic.WARNING, "i"),
				matches(Diagnostic.WARNING, "o"),
				matches(Diagnostic.ERROR, "u")));
		}

	}

	@RunWith(JUnit4.class)
	public static class Unlimited extends DiagnosticFrequencyMap_Test {

		/**
		 * Initializes me.
		 */
		public Unlimited() {
			super(DiagnosticFrequencyMap.unlimited());
		}

		@Test
		public void isEmpty() {
			assertThat("should be empty", fixture().isEmpty(), is(true));
			charStream("abcdefghijklmnop").map(this::error).forEach(fixture()::add);
			assertThat("should not be empty", fixture().isEmpty(), is(false));
		}

		@Test
		public void isFull() {
			charStream("abcdefghijklmnop").map(this::error).forEach(fixture()::add);
			assertThat("unlimited map should never be full", fixture().isFull(), is(false));
		}

		@Test
		public void size() {
			assertThat(fixture().size(), is(0));
			charStream("abcdefghijklmnop").map(this::error).forEach(fixture()::add);
			assertThat(fixture().size(), is(16));
		}

		@Test
		public void getDiscardedSeverity() {
			// Initial conditions
			assertThat(fixture().getDiscardedSeverity(), is(Diagnostic.OK));

			charStream("abcde").map(this::info).forEach(fixture()::add);
			assertThat("nothing should ever be discarded", fixture().getDiscardedSeverity(), is(Diagnostic.OK));

			charStream("fghij").map(this::warning).forEach(fixture()::add);
			assertThat("nothing should ever be discarded", fixture().getDiscardedSeverity(), is(Diagnostic.OK));

			charStream("klmno").map(this::error).forEach(fixture()::add);
			assertThat("nothing should ever be discarded", fixture().getDiscardedSeverity(), is(Diagnostic.OK));

			charStream("p").map(this::error).forEach(fixture()::add);
			assertThat("nothing should ever be discarded", fixture().getDiscardedSeverity(), is(Diagnostic.OK));
		}

		@Test
		public void appendTo() {
			// Initial conditions
			final List<Diagnostic> diagnostics = new ArrayList<>();
			fixture().appendTo(diagnostics);
			assertThat(diagnostics, not(hasItem(anything())));
fixture().addAll(charStream("abcde").map(this::info).collect(toList())); diagnostics.clear(); fixture().appendTo(diagnostics); assertThat(diagnostics, everyItem(matches(Diagnostic.INFO, substringOf("abcde")))); fixture().addAll(charStream("fghij").map(this::warning).collect(toList())); diagnostics.clear(); fixture().appendTo(diagnostics); assertThat(diagnostics.subList(0, 5), everyItem(matches(Diagnostic.WARNING, substringOf("fghij")))); assertThat(diagnostics.subList(5, 10), everyItem(matches(Diagnostic.INFO, substringOf("abcde")))); fixture().addAll(charStream("klmno").map(this::error).collect(toList())); diagnostics.clear(); fixture().appendTo(diagnostics); assertThat(diagnostics.subList(0, 5), everyItem(matches(Diagnostic.ERROR, substringOf("klmno")))); assertThat(diagnostics.subList(5, 10), everyItem(matches(Diagnostic.WARNING, substringOf("fghij")))); assertThat(diagnostics.subList(10, 15), everyItem(matches(Diagnostic.INFO, substringOf("abcde")))); fixture().add(error("p")); diagnostics.clear(); fixture().appendTo(diagnostics); assertThat("Sixth diagnostic should be the error added to the earlier five", diagnostics.get(5), matches(Diagnostic.ERROR, "p")); } @Test public void iterator() { // Initial conditions List<Diagnostic> diagnostics = iterate(fixture()); assertThat(diagnostics, not(hasItem(anything()))); fixture().addAll(charStream("abcde").map(this::info).collect(toList())); diagnostics = iterate(fixture()); assertThat(diagnostics, everyItem(matches(Diagnostic.INFO, substringOf("abcde")))); fixture().addAll(charStream("fghij").map(this::warning).collect(toList())); diagnostics = iterate(fixture()); assertThat(diagnostics.subList(0, 5), everyItem(matches(Diagnostic.WARNING, substringOf("fghij")))); assertThat(diagnostics.subList(5, 10), everyItem(matches(Diagnostic.INFO, substringOf("abcde")))); fixture().addAll(charStream("klmno").map(this::error).collect(toList())); diagnostics = iterate(fixture()); assertThat(diagnostics.subList(0, 5), everyItem(matches(Diagnostic.ERROR, substringOf("klmno")))); assertThat(diagnostics.subList(5, 10), everyItem(matches(Diagnostic.WARNING, substringOf("fghij")))); assertThat(diagnostics.subList(10, 15), everyItem(matches(Diagnostic.INFO, substringOf("abcde")))); fixture().add(error("p")); diagnostics = iterate(fixture()); assertThat("Sixth diagnostic should be the error added to the earlier five", diagnostics.get(5), matches(Diagnostic.ERROR, "p")); } @Test public void clear() { charStream("abc").map(this::info).forEach(fixture()::add); charStream("def").map(this::warning).forEach(fixture()::add); charStream("ghi").map(this::error).forEach(fixture()::add); fixture().clear(); assertThat("not empty", fixture().isEmpty(), is(true)); assertThat("somehow full", fixture().isFull(), is(false)); assertThat("has size", fixture().size(), is(0)); assertThat("something discarded from nothing", fixture().getDiscardedSeverity(), is(Diagnostic.OK)); } @SuppressWarnings("unchecked") @Test public void addDiagnosticFilter() { final Set<String> vowels = charStream("aeiou").collect(toSet()); final Predicate<Diagnostic> isVowel = d -> vowels.contains(d.getMessage()); final Predicate<Diagnostic> isProblem = d -> d.getSeverity() > Diagnostic.INFO; fixture().addDiagnosticFilter(isVowel); fixture().addDiagnosticFilter(isProblem); // initial conditions assumeThat(fixture().size(), is(0)); assumeThat(fixture().getDiscardedSeverity(), is(Diagnostic.OK)); charStream("abcd").map(this::info).forEach(fixture()::add); assertThat(fixture().size(), is(0)); assertThat(fixture().getDiscardedSeverity(), is(Diagnostic.INFO)); charStream("efghijklmnop").map(this::warning).forEach(fixture()::add); assertThat(fixture().size(), is(3)); assertThat(fixture().getDiscardedSeverity(), is(Diagnostic.WARNING)); charStream("qrstuvwxyz").map(this::error).forEach(fixture()::add); assertThat(fixture().size(), is(4)); assertThat(fixture().getDiscardedSeverity(), is(Diagnostic.ERROR)); final List<Diagnostic> collected = iterate(fixture()); assertThat(collected, hasItems( matches(Diagnostic.WARNING, "e"), matches(Diagnostic.WARNING, "i"), matches(Diagnostic.WARNING, "o"), matches(Diagnostic.ERROR, "u"))); } } // // Common test framework // final DiagnosticFrequencyMap fixture() { return fixture; } /** * Iterate a diagnostic {@code freq}uency map to collect its diagnostics. * * @param freq the map to {@linkplain Iterable#iterator() iterate} * @return the diagnostics gathered from the iterator */ final List<Diagnostic> iterate(DiagnosticFrequencyMap freq) { final List<Diagnostic> result = new ArrayList<>(freq.size()); for (final Diagnostic next : freq) { result.add(next); } return result; } final Stream<String> charStream(String chars) { return chars.chars().mapToObj(Character::toChars).map(String::new); } final Diagnostic diagnostic(int severity, String message) { return new BasicDiagnostic(severity, "org.eclipse.emfforms.common.tests", 0, message, null); } final Diagnostic error(String message) { return diagnostic(Diagnostic.ERROR, message); } final Diagnostic warning(String message) { return diagnostic(Diagnostic.WARNING, message); } final Diagnostic info(String message) { return diagnostic(Diagnostic.INFO, message); } final Matcher<Diagnostic> matches(int severityMask, Matcher<String> message) { return new TypeSafeDiagnosingMatcher<Diagnostic>() { @Override protected boolean matchesSafely(Diagnostic item, Description mismatchDescription) { if ((severityMask & item.getSeverity()) != item.getSeverity()) { mismatchDescription.appendText(String.format("severity does not match %x mask", severityMask)); //$NON-NLS-1$ return false; } if (!message.matches(item.getMessage())) { message.describeMismatch(item.getMessage(), mismatchDescription); return false; } return true; } @Override public void describeTo(Description description) { description.appendText( String.format("diagnostic of severity matching %x mask with message that ", severityMask)); //$NON-NLS-1$ description.appendDescriptionOf(message); } }; } final Matcher<Diagnostic> matches(int severityMask, String message) { return matches(severityMask, is(message)); } /** * Obtain a matcher that matches strings that are sub-strings of some target string. * * @param s the target string * @return a matcher of strings that are substrings of {@code s} */ final Matcher<String> substringOf(String s) { return new TypeSafeDiagnosingMatcher<String>() { @Override protected boolean matchesSafely(String item, Description mismatchDescription) { final boolean result = s.contains(item); if (!result) { mismatchDescription.appendText(String.format("\"%s\" is not contained in \"%s\"", item, s)); //$NON-NLS-1$ } return result; } @Override public void describeTo(Description description) { description.appendText(String.format("string contained in \"%s\"", s)); //$NON-NLS-1$ } }; } }