changeset 43259:1a8c1621084d

8170250: update/improve testing of classfile module attribute Reviewed-by: jjg, jlahoda
author anazarov
date Wed, 18 Jan 2017 21:09:19 +0300
parents 45757c4367f2
children f5b52e571607
files langtools/test/tools/javac/classfiles/attributes/Module/ModuleTest.java langtools/test/tools/javac/classfiles/attributes/Module/ModuleTestBase.java langtools/test/tools/javac/classfiles/attributes/lib/TestResult.java
diffstat 3 files changed, 290 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/langtools/test/tools/javac/classfiles/attributes/Module/ModuleTest.java	Wed Jan 18 09:35:23 2017 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/Module/ModuleTest.java	Wed Jan 18 21:09:19 2017 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,7 +24,7 @@
 /*
  * @test
  * @summary Module attribute tests
- * @bug 8080878 8161906 8162713
+ * @bug 8080878 8161906 8162713 8170250
  * @modules java.compiler
  *          jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
@@ -53,6 +53,28 @@
     }
 
     @Test
+    public void testOpenEmptyModule(Path base) throws Exception {
+        ModuleDescriptor moduleDescriptor = new ModuleDescriptor("m", ModuleFlag.OPEN)
+                .write(base);
+        compile(base);
+        testModuleAttribute(base, moduleDescriptor);
+    }
+
+    @Test
+    public void testModuleName(Path base) throws Exception {
+        testName("module.name", base.resolve("dot"));
+        testName("module.exports.component.subcomponent.more.dots", base.resolve("dots"));
+        testName("moduleName", base.resolve("noDots"));
+    }
+
+    private void testName(String name, Path path) throws Exception{
+        ModuleDescriptor moduleDescriptor = new ModuleDescriptor(name)
+                .write(path);
+        compile(path);
+        testModuleAttribute(path, moduleDescriptor);
+    }
+
+    @Test
     public void testExports(Path base) throws Exception {
         ModuleDescriptor moduleDescriptor = new ModuleDescriptor("m")
                 .exports("pack")
@@ -92,16 +114,6 @@
     }
 
     @Test
-    public void testQualifiedDynamicExports(Path base) throws Exception {
-        ModuleDescriptor moduleDescriptor = new ModuleDescriptor("m")
-                .exportsTo("pack", "jdk.compiler")
-                .write(base);
-        tb.writeJavaFiles(base, "package pack; public class A { }");
-        compile(base);
-        testModuleAttribute(base, moduleDescriptor);
-    }
-
-    @Test
     public void testSeveralQualifiedExports(Path base) throws Exception {
         ModuleDescriptor moduleDescriptor = new ModuleDescriptor("m")
                 .exportsTo("pack", "jdk.compiler, jdk.jdeps")
@@ -121,6 +133,47 @@
     }
 
     @Test
+    public void testOpens(Path base) throws Exception {
+        ModuleDescriptor moduleDescriptor = new ModuleDescriptor("module.name")
+                .opens("pack")
+                .write(base);
+        tb.writeJavaFiles(base, "package pack; public class C extends java.util.ArrayList{ }");
+        compile(base);
+        testModuleAttribute(base, moduleDescriptor);
+    }
+
+    @Test
+    public void testQualifiedOpens(Path base) throws Exception {
+        ModuleDescriptor moduleDescriptor = new ModuleDescriptor("m")
+                .opensTo("pack", "jdk.compiler")
+                .write(base);
+        tb.writeJavaFiles(base, "package pack; public class A { }");
+        compile(base);
+        testModuleAttribute(base, moduleDescriptor);
+    }
+
+    @Test
+    public void testSeveralOpens(Path base) throws Exception {
+        ModuleDescriptor moduleDescriptor = new ModuleDescriptor("module.m1.name")
+                .opensTo("pack", "jdk.compiler, jdk.jdeps")
+                .opensTo("pack2", "jdk.jdeps")
+                .opensTo("pack3", "jdk.compiler")
+                .opensTo("pack4", "jdk.compiler, jdk.jdeps")
+                .opensTo("pack5", "jdk.compiler")
+                .opens("pack6")
+                .write(base);
+        tb.writeJavaFiles(base,
+                "package pack; public class A {}",
+                "package pack2; public class B {}",
+                "package pack3; public class C {}",
+                "package pack4; public class C {}",
+                "package pack5; public class C {}",
+                "package pack6; public class C {}");
+        compile(base);
+        testModuleAttribute(base, moduleDescriptor);
+    }
+
+    @Test
     public void testRequires(Path base) throws Exception {
         ModuleDescriptor moduleDescriptor = new ModuleDescriptor("m")
                 .requires("jdk.compiler")
@@ -182,10 +235,12 @@
                 .provides("java.util.Collection", "pack2.D")
                 .provides("java.util.List", "pack2.D")
                 .requires("jdk.compiler")
+                .provides("javax.tools.FileObject", "pack2.E")
                 .provides("com.sun.tools.javac.Main", "pack2.C")
                 .write(base);
         tb.writeJavaFiles(base, "package pack2; public class D extends java.util.ArrayList{ }",
-                "package pack2; public class C extends com.sun.tools.javac.Main{ }");
+                "package pack2; public class C extends com.sun.tools.javac.Main{ }",
+                "package pack2; public class E extends javax.tools.SimpleJavaFileObject{ public E(){ super(null,null); } }");
         compile(base);
         testModuleAttribute(base, moduleDescriptor);
     }
@@ -203,9 +258,10 @@
     public void testSeveralUses(Path base) throws Exception {
         ModuleDescriptor moduleDescriptor = new ModuleDescriptor("m")
                 .uses("java.util.List")
-                .uses("java.util.Collection")
+                .uses("java.util.Collection") // from java.base
                 .requires("jdk.compiler")
-                .uses("javax.tools.JavaCompiler")
+                .uses("javax.tools.JavaCompiler") // from java.compiler
+                .uses("com.sun.tools.javac.Main") // from jdk.compiler
                 .write(base);
         compile(base);
         testModuleAttribute(base, moduleDescriptor);
@@ -216,9 +272,10 @@
         Path m1 = base.resolve("m1x");
         ModuleDescriptor moduleDescriptor = new ModuleDescriptor("m1x")
                 .exports("pack1")
-                .exports("pack3")
+                .opens("pack3")
                 .exportsTo("packTo1", "m2x")
-                .exportsTo("packTo3", "m3x")
+                .opensTo("packTo1", "m2x") // the same as exportsTo
+                .opensTo("packTo3", "m3x")
                 .requires("jdk.compiler")
                 .requires("m2x", RequiresFlag.TRANSITIVE)
                 .requires("m3x", RequiresFlag.STATIC)
@@ -230,9 +287,49 @@
                 .requires("m5x", RequiresFlag.STATIC)
                 .requires("m6x", RequiresFlag.TRANSITIVE)
                 .requires("java.compiler")
-                .exportsTo("packTo4", "java.compiler")
+                .opensTo("packTo4", "java.compiler")
                 .exportsTo("packTo2", "java.compiler")
-                .exports("pack4")
+                .opens("pack2") // same as exports
+                .opens("pack4")
+                .exports("pack2")
+                .write(m1);
+        tb.writeJavaFiles(m1, "package pack1; public class C extends java.util.ArrayList{ }",
+                "package pack2; public class D extends java.util.ArrayList{ }",
+                "package pack3; public class D extends java.util.ArrayList{ }",
+                "package pack4; public class D extends java.util.ArrayList{ }");
+        tb.writeJavaFiles(m1,
+                "package packTo1; public class T1 {}",
+                "package packTo2; public class T2 {}",
+                "package packTo3; public class T3 {}",
+                "package packTo4; public class T4 {}");
+        tb.writeJavaFiles(base.resolve("m2x"), "module m2x { }");
+        tb.writeJavaFiles(base.resolve("m3x"), "module m3x { }");
+        tb.writeJavaFiles(base.resolve("m4x"), "module m4x { }");
+        tb.writeJavaFiles(base.resolve("m5x"), "module m5x { }");
+        tb.writeJavaFiles(base.resolve("m6x"), "module m6x { }");
+        compile(base, "--module-source-path", base.toString(),
+                "-d", base.toString());
+        testModuleAttribute(m1, moduleDescriptor);
+    }
+
+    @Test
+    public void testOpenComplexModule(Path base) throws Exception {
+        Path m1 = base.resolve("m1x");
+        ModuleDescriptor moduleDescriptor = new ModuleDescriptor("m1x", ModuleFlag.OPEN)
+                .exports("pack1")
+                .exportsTo("packTo1", "m2x")
+                .requires("jdk.compiler")
+                .requires("m2x", RequiresFlag.TRANSITIVE)
+                .requires("m3x", RequiresFlag.STATIC)
+                .requires("m4x", RequiresFlag.TRANSITIVE, RequiresFlag.STATIC)
+                .provides("java.util.List", "pack1.C", "pack2.D")
+                .uses("java.util.List")
+                .uses("java.nio.file.Path")
+                .requires("jdk.jdeps", RequiresFlag.STATIC, RequiresFlag.TRANSITIVE)
+                .requires("m5x", RequiresFlag.STATIC)
+                .requires("m6x", RequiresFlag.TRANSITIVE)
+                .requires("java.compiler")
+                .exportsTo("packTo2", "java.compiler")
                 .exports("pack2")
                 .write(m1);
         tb.writeJavaFiles(m1, "package pack1; public class C extends java.util.ArrayList{ }",
--- a/langtools/test/tools/javac/classfiles/attributes/Module/ModuleTestBase.java	Wed Jan 18 09:35:23 2017 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/Module/ModuleTestBase.java	Wed Jan 18 21:09:19 2017 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,6 @@
 import com.sun.tools.classfile.ConstantPool;
 import com.sun.tools.classfile.ConstantPoolException;
 import com.sun.tools.classfile.Module_attribute;
-import com.sun.tools.javac.util.Pair;
 
 import java.io.IOException;
 import java.lang.annotation.Retention;
@@ -36,11 +35,11 @@
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
@@ -74,20 +73,30 @@
         ClassFile classFile = ClassFile.read(modulePath.resolve("module-info.class"));
         Module_attribute moduleAttribute = (Module_attribute) classFile.getAttribute("Module");
         ConstantPool constantPool = classFile.constant_pool;
-
+        testModuleName(moduleDescriptor, moduleAttribute, constantPool);
+        testModuleFlags(moduleDescriptor, moduleAttribute);
         testRequires(moduleDescriptor, moduleAttribute, constantPool);
         testExports(moduleDescriptor, moduleAttribute, constantPool);
+        testOpens(moduleDescriptor, moduleAttribute, constantPool);
         testProvides(moduleDescriptor, moduleAttribute, constantPool);
         testUses(moduleDescriptor, moduleAttribute, constantPool);
     }
 
+    private void testModuleName(ModuleDescriptor moduleDescriptor, Module_attribute module, ConstantPool constantPool) throws ConstantPoolException {
+        tr.checkEquals(constantPool.getModuleInfo(module.module_name).getName(), moduleDescriptor.name, "Unexpected module name");
+    }
+
+    private void testModuleFlags(ModuleDescriptor moduleDescriptor, Module_attribute module) {
+        tr.checkEquals(module.module_flags, moduleDescriptor.flags, "Unexpected module flags");
+    }
+
     private void testRequires(ModuleDescriptor moduleDescriptor, Module_attribute module, ConstantPool constantPool) throws ConstantPoolException {
         tr.checkEquals(module.requires_count, moduleDescriptor.requires.size(), "Wrong amount of requires.");
 
-        List<Pair<String, Integer>> actualRequires = new ArrayList<>();
+        List<Requires> actualRequires = new ArrayList<>();
         for (Module_attribute.RequiresEntry require : module.requires) {
-            actualRequires.add(Pair.of(
-                    require.getRequires(constantPool).replace('/', '.'),
+            actualRequires.add(new Requires(
+                    require.getRequires(constantPool),
                     require.requires_flags));
         }
         tr.checkContains(actualRequires, moduleDescriptor.requires, "Lists of requires don't match");
@@ -104,18 +113,36 @@
                 tr.checkEquals(export.exports_to_count, expectedTo.size(), "Wrong amount of exports to");
                 List<String> actualTo = new ArrayList<>();
                 for (int toIdx : export.exports_to_index) {
-                    actualTo.add(constantPool.getModuleInfo(toIdx).getName().replace('/', '.'));
+                    actualTo.add(constantPool.getModuleInfo(toIdx).getName());
                 }
                 tr.checkContains(actualTo, expectedTo, "Lists of \"exports to\" don't match.");
             }
         }
     }
 
+    private void testOpens(ModuleDescriptor moduleDescriptor, Module_attribute module, ConstantPool constantPool) throws ConstantPoolException {
+        tr.checkEquals(module.opens_count, moduleDescriptor.opens.size(), "Wrong amount of opens.");
+        for (Module_attribute.OpensEntry open : module.opens) {
+            String pkg = constantPool.getPackageInfo(open.opens_index).getName();
+            if (tr.checkTrue(moduleDescriptor.opens.containsKey(pkg), "Unexpected open " + pkg)) {
+                Open expectedOpen = moduleDescriptor.opens.get(pkg);
+                tr.checkEquals(expectedOpen.mask, open.opens_flags, "Wrong open flags");
+                List<String> expectedTo = expectedOpen.to;
+                tr.checkEquals(open.opens_to_count, expectedTo.size(), "Wrong amount of opens to");
+                List<String> actualTo = new ArrayList<>();
+                for (int toIdx : open.opens_to_index) {
+                    actualTo.add(constantPool.getModuleInfo(toIdx).getName());
+                }
+                tr.checkContains(actualTo, expectedTo, "Lists of \"opens to\" don't match.");
+            }
+        }
+    }
+
     private void testUses(ModuleDescriptor moduleDescriptor, Module_attribute module, ConstantPool constantPool) throws ConstantPoolException {
         tr.checkEquals(module.uses_count, moduleDescriptor.uses.size(), "Wrong amount of uses.");
         List<String> actualUses = new ArrayList<>();
         for (int usesIdx : module.uses_index) {
-            String uses = constantPool.getClassInfo(usesIdx).getBaseName().replace('/', '.');
+            String uses = constantPool.getClassInfo(usesIdx).getBaseName();
             actualUses.add(uses);
         }
         tr.checkContains(actualUses, moduleDescriptor.uses, "Lists of uses don't match");
@@ -131,10 +158,10 @@
         tr.checkEquals(moduleProvidesCount, moduleDescriptorProvidesCount, "Wrong amount of provides.");
         Map<String, List<String>> actualProvides = new HashMap<>();
         for (Module_attribute.ProvidesEntry provide : module.provides) {
-            String provides = constantPool.getClassInfo(provide.provides_index).getBaseName().replace('/', '.');
+            String provides = constantPool.getClassInfo(provide.provides_index).getBaseName();
             List<String> impls = new ArrayList<>();
             for (int i = 0; i < provide.with_count; i++) {
-                String with = constantPool.getClassInfo(provide.with_index[i]).getBaseName().replace('/', '.');
+                String with = constantPool.getClassInfo(provide.with_index[i]).getBaseName();
                 impls.add(with);
             }
             actualProvides.put(provides, impls);
@@ -163,9 +190,27 @@
         int getMask();
     }
 
+    public enum ModuleFlag implements Mask {
+        OPEN("open", Module_attribute.ACC_OPEN);
+
+        private final String token;
+        private final int mask;
+
+        ModuleFlag(String token, int mask) {
+            this.token = token;
+            this.mask = mask;
+        }
+
+        @Override
+        public int getMask() {
+            return mask;
+        }
+    }
+
     public enum RequiresFlag implements Mask {
         TRANSITIVE("transitive", Module_attribute.ACC_TRANSITIVE),
-        STATIC("static", Module_attribute.ACC_STATIC_PHASE);
+        STATIC("static", Module_attribute.ACC_STATIC_PHASE),
+        MANDATED("", Module_attribute.ACC_MANDATED);
 
         private final String token;
         private final int mask;
@@ -181,13 +226,30 @@
         }
     }
 
-    public enum ExportFlag implements Mask {
+    public enum ExportsFlag implements Mask {
         SYNTHETIC("", Module_attribute.ACC_SYNTHETIC);
 
         private final String token;
         private final int mask;
 
-        ExportFlag(String token, int mask) {
+        ExportsFlag(String token, int mask) {
+            this.token = token;
+            this.mask = mask;
+        }
+
+        @Override
+        public int getMask() {
+            return mask;
+        }
+    }
+
+    public enum OpensFlag implements Mask {
+        SYNTHETIC("", Module_attribute.ACC_SYNTHETIC);
+
+        private final String token;
+        private final int mask;
+
+        OpensFlag(String token, int mask) {
             this.token = token;
             this.mask = mask;
         }
@@ -199,27 +261,64 @@
     }
 
     private class Export {
-        String pkg;
-        int mask;
-        List<String> to = new ArrayList<>();
+        private final String pkg;
+        private final int mask;
+        private final List<String> to = new ArrayList<>();
 
-        public Export(String pkg, int mask) {
+        Export(String pkg, int mask) {
             this.pkg = pkg;
             this.mask = mask;
         }
     }
 
+    private class Open {
+        private final String pkg;
+        private final int mask;
+        private final List<String> to = new ArrayList<>();
+
+        Open(String pkg, int mask) {
+            this.pkg = pkg;
+            this.mask = mask;
+        }
+    }
+
+    private class Requires {
+        private final String module;
+        private final int mask;
+
+        Requires(String module, int mask) {
+            this.module = module;
+            this.mask = mask;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            Requires requires = (Requires) o;
+            return mask == requires.mask &&
+                    Objects.equals(module, requires.module);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(module, mask);
+        }
+    }
+
     protected class ModuleDescriptor {
 
         private final String name;
-        //pair is name of module and flag(public,mandated,synthetic)
-        private final List<Pair<String, Integer>> requires = new ArrayList<>();
+        private final int flags;
+
+        private final List<Requires> requires = new ArrayList<>();
 
         {
-            requires.add(new Pair<>("java.base", Module_attribute.ACC_MANDATED));
+            requires.add(new Requires("java.base", computeMask(RequiresFlag.MANDATED)));
         }
 
         private final Map<String, Export> exports = new HashMap<>();
+        private final Map<String, Open> opens = new HashMap<>();
 
         //List of service and implementation
         private final Map<String, List<String>> provides = new LinkedHashMap<>();
@@ -227,22 +326,26 @@
 
         private static final String LINE_END = ";\n";
 
-        StringBuilder content = new StringBuilder("module ");
+        StringBuilder content = new StringBuilder("");
 
-        public ModuleDescriptor(String moduleName) {
+        public ModuleDescriptor(String moduleName, ModuleFlag... flags) {
             this.name = moduleName;
-            content.append(name).append('{').append('\n');
+            this.flags = computeMask(flags);
+            for (ModuleFlag flag : flags) {
+                content.append(flag.token).append(" ");
+            }
+            content.append("module ").append(moduleName).append('{').append('\n');
         }
 
         public ModuleDescriptor requires(String module) {
-            this.requires.add(Pair.of(module, 0));
+            this.requires.add(new Requires(module, 0));
             content.append("    requires ").append(module).append(LINE_END);
 
             return this;
         }
 
         public ModuleDescriptor requires(String module, RequiresFlag... flags) {
-            this.requires.add(new Pair<>(module, computeMask(flags)));
+            this.requires.add(new Requires(module, computeMask(flags)));
 
             content.append("    requires ");
             for (RequiresFlag flag : flags) {
@@ -253,26 +356,52 @@
             return this;
         }
 
-        public ModuleDescriptor exports(String pkg, ExportFlag... flags) {
-            this.exports.putIfAbsent(pkg, new Export(pkg, computeMask(flags)));
+        public ModuleDescriptor exports(String pkg, ExportsFlag... flags) {
+            this.exports.put(toInternalForm(pkg), new Export(toInternalForm(pkg), computeMask(flags)));
             content.append("    exports ");
-            for (ExportFlag flag : flags) {
+            for (ExportsFlag flag : flags) {
                 content.append(flag.token).append(" ");
             }
             content.append(pkg).append(LINE_END);
             return this;
         }
 
-        public ModuleDescriptor exportsTo(String pkg, String to, ExportFlag... flags) {
+        public ModuleDescriptor exportsTo(String pkg, String to, ExportsFlag... flags) {
             List<String> tos = Pattern.compile(",")
                     .splitAsStream(to)
                     .map(String::trim)
                     .collect(Collectors.toList());
-            this.exports.computeIfAbsent(pkg, k -> new Export(pkg, computeMask(flags)))
+            this.exports.compute(toInternalForm(pkg), (k,v) -> new Export(k, computeMask(flags)))
                     .to.addAll(tos);
 
             content.append("    exports ");
-            for (ExportFlag flag : flags) {
+            for (ExportsFlag flag : flags) {
+                content.append(flag.token).append(" ");
+            }
+            content.append(pkg).append(" to ").append(to).append(LINE_END);
+            return this;
+        }
+
+        public ModuleDescriptor opens(String pkg, OpensFlag... flags) {
+            this.opens.put(toInternalForm(pkg), new Open(toInternalForm(pkg), computeMask(flags)));
+            content.append("    opens ");
+            for (OpensFlag flag : flags) {
+                content.append(flag.token).append(" ");
+            }
+            content.append(pkg).append(LINE_END);
+            return this;
+        }
+
+        public ModuleDescriptor opensTo(String pkg, String to, OpensFlag... flags) {
+            List<String> tos = Pattern.compile(",")
+                    .splitAsStream(to)
+                    .map(String::trim)
+                    .collect(Collectors.toList());
+            this.opens.compute(toInternalForm(pkg), (k,v) -> new Open(toInternalForm(k), computeMask(flags)))
+                    .to.addAll(tos);
+
+            content.append("    opens ");
+            for (OpensFlag flag : flags) {
                 content.append(flag.token).append(" ");
             }
             content.append(pkg).append(" to ").append(to).append(LINE_END);
@@ -280,7 +409,10 @@
         }
 
         public ModuleDescriptor provides(String provides, String... with) {
-            this.provides.put(provides, Arrays.asList(with));
+            List<String> impls = Arrays.stream(with)
+                    .map(this::toInternalForm)
+                    .collect(Collectors.toList());
+            this.provides.put(toInternalForm(provides), impls);
             content.append("    provides ")
                     .append(provides)
                     .append(" with ")
@@ -290,8 +422,8 @@
         }
 
         public ModuleDescriptor uses(String... uses) {
-            Collections.addAll(this.uses, uses);
             for (String use : uses) {
+                this.uses.add(toInternalForm(use));
                 content.append("    uses ").append(use).append(LINE_END);
             }
             return this;
@@ -305,7 +437,11 @@
             return this;
         }
 
-        private int computeMask(Mask[] masks) {
+        private String toInternalForm(String name) {
+            return name.replace('.', '/');
+        }
+
+        private int computeMask(Mask... masks) {
             return Arrays.stream(masks)
                     .map(Mask::getMask)
                     .reduce((a, b) -> a | b)
--- a/langtools/test/tools/javac/classfiles/attributes/lib/TestResult.java	Wed Jan 18 09:35:23 2017 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/lib/TestResult.java	Wed Jan 18 21:09:19 2017 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -82,7 +82,8 @@
         Set<?> copy = new HashSet<>(expected);
         copy.removeAll(found);
         if (!found.containsAll(expected)) {
-            return checkTrue(false, message + " FAIL : not found elements : " + copy);
+            return checkTrue(false, message + " FAIL : not found elements : " + copy + "\n" +
+                    "Actual: " + found);
         } else {
             return checkTrue(true, message + " PASS : all elements found");
         }