diff --git a/message/message-web/pom.xml b/message/message-web/pom.xml index 12f2be6673..ec24a5d0ac 100644 --- a/message/message-web/pom.xml +++ b/message/message-web/pom.xml @@ -55,7 +55,15 @@ 92 - + + org.apache.maven.plugins + maven-compiler-plugin + + 11 + 11 + + + diff --git a/message/message-web/src/main/java/com/mastercard/test/flow/msg/web/WebSequence.java b/message/message-web/src/main/java/com/mastercard/test/flow/msg/web/WebSequence.java index d2c304ddb0..e0262e0350 100644 --- a/message/message-web/src/main/java/com/mastercard/test/flow/msg/web/WebSequence.java +++ b/message/message-web/src/main/java/com/mastercard/test/flow/msg/web/WebSequence.java @@ -43,8 +43,8 @@ public class WebSequence extends AbstractMessage { private static final ObjectMapper JSON = new ObjectMapper(); private final WebSequence parent; - - private final SortedMap>> operations = new TreeMap<>(); + private final SortedMap>> operations = new TreeMap<>(); private Map results; @@ -55,27 +55,28 @@ public WebSequence() { parent = null; } - private WebSequence(WebSequence parent) { + private WebSequence( WebSequence parent ) { this.parent = parent; } @Override public WebSequence child() { - return copyMasksTo(new WebSequence(self())); + return copyMasksTo( new WebSequence( self() ) ); } @Override - public WebSequence peer(byte[] bytes) { - WebSequence peer = copyMasksTo(new WebSequence(parent)); - peer.operations.putAll(operations); + public WebSequence peer( byte[] bytes ) { + WebSequence peer = copyMasksTo( new WebSequence( parent ) ); + peer.operations.putAll( operations ); try { - ((Map) JSON.readValue(bytes, Map.class)) - .forEach(peer::set); - } catch (IOException ioe) { - throw new UncheckedIOException(String.format( + ((Map) JSON.readValue( bytes, Map.class )) + .forEach( peer::set ); + } + catch( IOException ioe ) { + throw new UncheckedIOException( String.format( "Failed to parse '%s' (%s)", - new String(bytes, UTF_8), Arrays.toString(bytes)), - ioe); + new String( bytes, UTF_8 ), Arrays.toString( bytes ) ), + ioe ); } return peer; } @@ -83,9 +84,10 @@ public WebSequence peer(byte[] bytes) { @Override public byte[] content() { try { - return JSON.writeValueAsBytes(parameters()); - } catch (IOException ioe) { - throw new UncheckedIOException(ioe); + return JSON.writeValueAsBytes( parameters() ); + } + catch( IOException ioe ) { + throw new UncheckedIOException( ioe ); } } @@ -95,50 +97,68 @@ protected String asHuman() { // use 'parameters()'. Map params = results != null ? results : parameters(); - // Find the maximum length of the parameter names. This is used for formatting. - int nameWidth = params.keySet().stream() - .mapToInt(String::length) - .max().orElse(1); + // Find the maximum length of the parameter names, values, and operations. This + // is used for formatting. + int nameWidth = Math.max( params.keySet().stream() + .mapToInt( String::length ) + .max().orElse( 1 ), "Parameters".length() ); + int valueWidth = Math.max( params.values().stream() + .flatMap( value -> Stream.of( value.split( "\n" ) ) ) + .mapToInt( String::length ) + .max().orElse( 1 ), "Values".length() ); + int operationsWidth = Math.max( operations().keySet().stream() + .mapToInt( String::length ) + .max().orElse( 1 ), "Operations".length() ); // Define the format for name-value pairs and padding for multi-line values. - String nvpFmt = " │ %" + nameWidth + "s │ %s │"; - String padFmt = "\n │ %" + nameWidth + "s "; - String pad = String.format(padFmt, ""); + String nvpFmt = "│ %" + nameWidth + "s │ %" + valueWidth + "s │"; + String padFmt = "\n│ %" + nameWidth + "s │ %-" + valueWidth + "s │"; // Create the formatted string for operations. String operationsStr = operations().keySet().stream() - .map(o -> " │ " + o + " │") - .collect(Collectors.joining("\n")); + .map( o -> String.format( "│ %" + operationsWidth + "s │", o ) ) + .collect( Collectors.joining( "\n" ) ); // Create the formatted string for parameters. String paramsStr = params.entrySet().stream() - .map(e -> String.format(nvpFmt, - e.getKey(), - Stream.of(e.getValue().split("\n")) - .collect(Collectors.joining(pad)))) - .collect(Collectors.joining("\n")); - - // Create a borderline for the box drawing. - String border = "─".repeat(nameWidth + 4); - - // Return the final formatted string with box drawing characters. - return String.format("┌%s┐\n" - + "│ Operations │\n" - + "├%s┤\n" - + "%s\n" - + "└%s┘\n" - + "┌%s┐\n" - + "│ Parameters │ Values │\n" - + "├%s┤\n" - + "%s\n" - + "└%s┘", - border, border, operationsStr, border, - border, border, paramsStr, border); + .map( e -> { + String key = e.getKey(); + String value = e.getValue(); + String[] lines = value.split( "\n" ); + return String.format( nvpFmt, key, lines[0] ) + + Stream.of( lines ).skip( 1 ) + .map( line -> String.format( padFmt, "", line ) ) + .collect( Collectors.joining() ); + } ) + .collect( Collectors.joining( "\n" ) ); + + // Calculate the width for the box drawing based on the longest line in + // operations and parameters. + int maxOperationsWidth = Math.max( "│ Operations │".length(), + operationsStr.lines().mapToInt( String::length ).max().orElse( 0 ) ); + int maxParamsWidth = Math.max( "│ Parameters │ Values │".length(), + paramsStr.lines().mapToInt( String::length ).max().orElse( 0 ) ); + + String operationsBorder = "─".repeat( maxOperationsWidth - 2 ); + String parametersBorder = "─".repeat( maxParamsWidth - 2 ); + + // Conditionally include the top, middle, and bottom lines only when there is + // data. + String operationsBox = operationsStr.isEmpty() ? "│ Operations │\n" + : String.format( "┌%s┐\n│ %-" + (maxOperationsWidth - 4) + "s │\n├%s┤\n%s\n└%s┘\n", + operationsBorder, + "Operations", operationsBorder, operationsStr, operationsBorder ); + String parametersBox = paramsStr.isEmpty() ? "│ Parameters │ Values │" + : String.format( "┌%s┐\n│ %-" + (maxParamsWidth - 4) + "s │\n├%s┤\n%s\n└%s┘", + parametersBorder, + "Parameters │ Values", parametersBorder, paramsStr, parametersBorder ); + + return operationsBox + parametersBox; } @Override public Set fields() { - return new TreeSet<>(parameters().keySet()); + return new TreeSet<>( parameters().keySet() ); } /** @@ -150,36 +170,37 @@ public Set fields() { * operation * @return this */ - public WebSequence operation(String name, - BiConsumer> op) { - operations.put(name, op); + public WebSequence operation( String name, + BiConsumer> op ) { + operations.put( name, op ); return self(); } @Override - protected Object access(String field) { - return parameters().get(field); + protected Object access( String field ) { + return parameters().get( field ); } private SortedMap>> operations() { SortedMap>> op = new TreeMap<>(); - if (parent != null) { - op.putAll(parent.operations()); + if( parent != null ) { + op.putAll( parent.operations() ); } - op.putAll(operations); + op.putAll( operations ); return op; } private Map parameters() { Map p = new TreeMap<>(); - if (parent != null) { - p.putAll(parent.parameters()); + if( parent != null ) { + p.putAll( parent.parameters() ); } - for (Update update : updates) { - if (update.value() == DELETE) { - p.remove(update.field()); - } else { - p.put(update.field(), String.valueOf(update.value())); + for( Update update : updates ) { + if( update.value() == DELETE ) { + p.remove( update.field() ); + } + else { + p.put( update.field(), String.valueOf( update.value() ) ); } } return p; @@ -191,33 +212,36 @@ private Map parameters() { * @param driver the browser to drive * @return The state of the parameters map after all operations have completed */ - public byte[] process(WebDriver driver) { + public byte[] process( WebDriver driver ) { Map params = parameters(); - operations().forEach((name, op) -> { - if (op != null) { + operations().forEach( ( name, op ) -> { + if( op != null ) { try { - op.accept(driver, params); - } catch (Exception e) { + op.accept( driver, params ); + } + catch( Exception e ) { // our operation has failed! String url = "No URL"; String source = "No page source"; try { url = driver.getCurrentUrl(); source = driver.getPageSource(); - } catch (Exception f) { + } + catch( Exception f ) { source = f.getMessage(); } - throw new IllegalStateException(String.format( + throw new IllegalStateException( String.format( "Operation '%s' failed on page '%s'\n%s", - name, url, source), - e); + name, url, source ), + e ); } } - }); + } ); try { - return JSON.writeValueAsBytes(params); - } catch (IOException ioe) { - throw new UncheckedIOException(ioe); + return JSON.writeValueAsBytes( params ); + } + catch( IOException ioe ) { + throw new UncheckedIOException( ioe ); } } diff --git a/message/message-web/src/test/java/com/mastercard/test/flow/msg/web/WebSequenceTest.java b/message/message-web/src/test/java/com/mastercard/test/flow/msg/web/WebSequenceTest.java index 2069185446..d5e497ae1c 100644 --- a/message/message-web/src/test/java/com/mastercard/test/flow/msg/web/WebSequenceTest.java +++ b/message/message-web/src/test/java/com/mastercard/test/flow/msg/web/WebSequenceTest.java @@ -29,11 +29,9 @@ class WebSequenceTest { @Test void empty() { WebSequence ws = new WebSequence(); - Assertions.assertEquals( "" - + "Operations:\n" - + "\n" - + "Parameters:\n" - + "", + Assertions.assertEquals( + "│ Operations │\n" + + "│ Parameters │ Values │", ws.assertable() ); } @@ -46,14 +44,16 @@ void unprocessed() { WebSequence ws = new WebSequence() .set( "foo", "bar" ) .set( "multiline", "so\nmany\nlines" ); - Assertions.assertEquals( "" - + "Operations:\n" - + "\n" - + "Parameters:\n" - + " foo : bar\n" - + " multiline : so\n" - + " many\n" - + " lines", + Assertions.assertEquals( + "│ Operations │\n" + + "┌─────────────────────┐\n" + + "│ Parameters │ Values │\n" + + "├─────────────────────┤\n" + + "│ foo │ bar │\n" + + "│ multiline │ so │\n" + + "│ │ many │\n" + + "│ │ lines │\n" + + "└─────────────────────┘", ws.assertable() ); } @@ -74,13 +74,19 @@ void processed() { WebSequence results = ws.peer( ws.process( null ) ); - Assertions.assertEquals( "" - + "Operations:\n" - + " param update\n" - + "Parameters:\n" - + " a : b\n" - + " c : i\n" - + " g : h", + Assertions.assertEquals( + "┌──────────────┐\n" + + "│ Operations │\n" + + "├──────────────┤\n" + + "│ param update │\n" + + "└──────────────┘\n" + + "┌─────────────────────┐\n" + + "│ Parameters │ Values │\n" + + "├─────────────────────┤\n" + + "│ a │ b │\n" + + "│ c │ i │\n" + + "│ g │ h │\n" + + "└─────────────────────┘", results.assertable() ); } @@ -127,11 +133,18 @@ void peer() { WebSequence peer = ws.peer( ws.content() ); - Assertions.assertEquals( "" - + "Operations:\n" - + " op\n" - + "Parameters:\n" - + " a : b", peer.assertable() ); + Assertions.assertEquals( + "┌────────────┐\n" + + "│ Operations │\n" + + "├────────────┤\n" + + "│ op │\n" + + "└────────────┘\n" + + "┌─────────────────────┐\n" + + "│ Parameters │ Values │\n" + + "├─────────────────────┤\n" + + "│ a │ b │\n" + + "└─────────────────────┘", + peer.assertable() ); Assertions.assertEquals( "Operation has not been invoked!", ref.get() ); @@ -170,11 +183,13 @@ void masking() { .masking( rng, m -> m.delete( "c" ) ); WebSequence peer = ws.peer( ws.content() ); - Assertions.assertEquals( "" - + "Operations:\n" - + "\n" - + "Parameters:\n" - + " a : b", + Assertions.assertEquals( + "│ Operations │\n" + + "┌─────────────────────┐\n" + + "│ Parameters │ Values │\n" + + "├─────────────────────┤\n" + + "│ a │ b │\n" + + "└─────────────────────┘", peer.assertable( rng ) ); } @@ -207,15 +222,21 @@ void sequence() { + "third operation invoked with {a=b, c=d}]", operations.toString() ); - Assertions.assertEquals( "" - + "Operations:\n" - + " first\n" - + " second\n" - + " third\n" - + "Parameters:\n" - + " a : b\n" - + " c : d\n" - + " e : f", + Assertions.assertEquals( + "┌────────────┐\n" + + "│ Operations │\n" + + "├────────────┤\n" + + "│ first │\n" + + "│ second │\n" + + "│ third │\n" + + "└────────────┘\n" + + "┌─────────────────────┐\n" + + "│ Parameters │ Values │\n" + + "├─────────────────────┤\n" + + "│ a │ b │\n" + + "│ c │ d │\n" + + "│ e │ f │\n" + + "└─────────────────────┘", results.assertable() ); }