/* * Copyright 2015-2017 the original author or authors. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution and is available at * * http://www.eclipse.org/legal/epl-v10.html */ package org.junit.platform.engine; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; import java.io.Serializable; import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.engine.UniqueId.Segment; /** * Used to {@link #parse} a {@link UniqueId} from a string representation * or to {@link #format} a {@link UniqueId} into a string representation. * * @since 1.0 */ class UniqueIdFormat implements Serializable { private static final long serialVersionUID = 1L; private static final UniqueIdFormat defaultFormat = new UniqueIdFormat('[', ':', ']', '/'); static UniqueIdFormat getDefault() { return defaultFormat; } private final char openSegment; private final char closeSegment; private final char segmentDelimiter; private final char typeValueSeparator; private final Pattern segmentPattern; UniqueIdFormat(char openSegment, char typeValueSeparator, char closeSegment, char segmentDelimiter) { this.openSegment = openSegment; this.typeValueSeparator = typeValueSeparator; this.closeSegment = closeSegment; this.segmentDelimiter = segmentDelimiter; this.segmentPattern = Pattern.compile( String.format("%s(.+)%s(.+)%s", quote(openSegment), quote(typeValueSeparator), quote(closeSegment))); } /** * Parse a {@code UniqueId} from the supplied string representation. * * @return a properly constructed {@code UniqueId} * @throws JUnitException if the string cannot be parsed */ UniqueId parse(String source) throws JUnitException { String[] parts = source.split(String.valueOf(this.segmentDelimiter)); List<Segment> segments = Arrays.stream(parts).map(this::createSegment).collect(toList()); return new UniqueId(this, segments); } private Segment createSegment(String segmentString) throws JUnitException { Matcher segmentMatcher = this.segmentPattern.matcher(segmentString); if (!segmentMatcher.matches()) { throw new JUnitException(String.format("'%s' is not a well-formed UniqueId segment", segmentString)); } String type = checkAllowed(segmentMatcher.group(1)); String value = checkAllowed(segmentMatcher.group(2)); return new Segment(type, value); } private String checkAllowed(String typeOrValue) { checkDoesNotContain(typeOrValue, this.segmentDelimiter); checkDoesNotContain(typeOrValue, this.typeValueSeparator); checkDoesNotContain(typeOrValue, this.openSegment); checkDoesNotContain(typeOrValue, this.closeSegment); return typeOrValue; } private void checkDoesNotContain(String typeOrValue, char forbiddenCharacter) { Preconditions.condition(typeOrValue.indexOf(forbiddenCharacter) < 0, () -> String.format("type or value '%s' must not contain '%s'", typeOrValue, forbiddenCharacter)); } /** * Format and return the string representation of the supplied {@code UniqueId}. */ String format(UniqueId uniqueId) { // @formatter:off return uniqueId.getSegments().stream() .map(this::describe) .collect(joining(String.valueOf(this.segmentDelimiter))); // @formatter:on } private String describe(Segment segment) { return String.format("%s%s%s%s%s", this.openSegment, segment.getType(), this.typeValueSeparator, segment.getValue(), this.closeSegment); } private static String quote(char c) { return Pattern.quote(String.valueOf(c)); } }