json/src/test/java/net/java/html/json/ModelProcessorTest.java
author Jaroslav Tulach <jtulach@netbeans.org>
Wed, 09 Dec 2015 21:39:13 +0100
changeset 1023 4f906bde3a2e
parent 1011 267ca1bfeb6f
permissions -rw-r--r--
#257039: @Model.instance() to allow storage of private (and non-JSON like) state in a model
     1 /**
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
     5  *
     6  * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
     7  * Other names may be trademarks of their respective owners.
     8  *
     9  * The contents of this file are subject to the terms of either the GNU
    10  * General Public License Version 2 only ("GPL") or the Common
    11  * Development and Distribution License("CDDL") (collectively, the
    12  * "License"). You may not use this file except in compliance with the
    13  * License. You can obtain a copy of the License at
    14  * http://www.netbeans.org/cddl-gplv2.html
    15  * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    16  * specific language governing permissions and limitations under the
    17  * License.  When distributing the software, include this License Header
    18  * Notice in each file and include the License file at
    19  * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    20  * particular file as subject to the "Classpath" exception as provided
    21  * by Oracle in the GPL Version 2 section of the License file that
    22  * accompanied this code. If applicable, add the following below the
    23  * License Header, with the fields enclosed by brackets [] replaced by
    24  * your own identifying information:
    25  * "Portions Copyrighted [year] [name of copyright owner]"
    26  *
    27  * Contributor(s):
    28  *
    29  * The Original Software is NetBeans. The Initial Developer of the Original
    30  * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
    31  *
    32  * If you wish your version of this file to be governed by only the CDDL
    33  * or only the GPL Version 2, indicate your decision by adding
    34  * "[Contributor] elects to include this software in this distribution
    35  * under the [CDDL or GPL Version 2] license." If you do not indicate a
    36  * single choice of license, a recipient has the option to distribute
    37  * your version of this file under either the CDDL, the GPL Version 2 or
    38  * to extend the choice of license to its licensees as provided above.
    39  * However, if you add GPL Version 2 code and therefore, elected the GPL
    40  * Version 2 license, then the option applies only if the new code is
    41  * made subject to such option by the copyright holder.
    42  */
    43 package net.java.html.json;
    44 
    45 import java.io.IOException;
    46 import java.util.Locale;
    47 import javax.tools.Diagnostic;
    48 import javax.tools.JavaFileObject;
    49 import static org.testng.Assert.*;
    50 import org.testng.annotations.Test;
    51 
    52 /** Verify errors emitted by the processor.
    53  *
    54  * @author Jaroslav Tulach
    55  */
    56 public class ModelProcessorTest {
    57     @Test public void verifyWrongType() throws IOException {
    58         String html = "<html><body>"
    59             + "</body></html>";
    60         String code = "package x.y.z;\n"
    61             + "import net.java.html.json.Model;\n"
    62             + "import net.java.html.json.Property;\n"
    63             + "@Model(className=\"XModel\", properties={\n"
    64             + "  @Property(name=\"prop\", type=Runnable.class)\n"
    65             + "})\n"
    66             + "class X {\n"
    67             + "}\n";
    68 
    69         Compile c = Compile.create(html, code);
    70         assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
    71         boolean ok = false;
    72         StringBuilder msgs = new StringBuilder();
    73         for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
    74             String msg = e.getMessage(Locale.ENGLISH);
    75             if (msg.contains("Runnable")) {
    76                 ok = true;
    77             }
    78             msgs.append("\n").append(msg);
    79         }
    80         if (!ok) {
    81             fail("Should contain warning about Runnable:" + msgs);
    82         }
    83     }
    84 
    85     @Test public void verifyWrongTypeInInnerClass() throws IOException {
    86         String html = "<html><body>"
    87             + "</body></html>";
    88         String code = "package x.y.z;\n"
    89             + "import net.java.html.json.Model;\n"
    90             + "import net.java.html.json.Property;\n"
    91             + "class X {\n"
    92             + "  @Model(className=\"XModel\", properties={\n"
    93             + "    @Property(name=\"prop\", type=Runnable.class)\n"
    94             + "  })\n"
    95             + "  static class Inner {\n"
    96             + "  }\n"
    97             + "}\n";
    98 
    99         Compile c = Compile.create(html, code);
   100         assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
   101         boolean ok = false;
   102         StringBuilder msgs = new StringBuilder();
   103         for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
   104             String msg = e.getMessage(Locale.ENGLISH);
   105             if (msg.contains("Runnable")) {
   106                 ok = true;
   107             }
   108             msgs.append("\n").append(msg);
   109         }
   110         if (!ok) {
   111             fail("Should contain warning about Runnable:" + msgs);
   112         }
   113     }
   114 
   115     @Test public void warnOnNonStatic() throws IOException {
   116         String html = "<html><body>"
   117             + "</body></html>";
   118         String code = "package x.y.z;\n"
   119             + "import net.java.html.json.Model;\n"
   120             + "import net.java.html.json.Property;\n"
   121             + "import net.java.html.json.ComputedProperty;\n"
   122             + "@Model(className=\"XModel\", properties={\n"
   123             + "  @Property(name=\"prop\", type=int.class)\n"
   124             + "})\n"
   125             + "class X {\n"
   126             + "    @ComputedProperty int y(int prop) {\n"
   127             + "        return prop;\n"
   128             + "    }\n"
   129             + "}\n";
   130 
   131         Compile c = Compile.create(html, code);
   132         assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
   133         boolean ok = false;
   134         StringBuilder msgs = new StringBuilder();
   135         for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
   136             String msg = e.getMessage(Locale.ENGLISH);
   137             if (msg.contains("y has to be static")) {
   138                 ok = true;
   139             }
   140             msgs.append("\n").append(msg);
   141         }
   142         if (!ok) {
   143             fail("Should contain warning about non-static method:" + msgs);
   144         }
   145     }
   146 
   147     @Test public void tooManyProperties() throws IOException {
   148         manyProperties(255, false, 0);
   149     }
   150 
   151     @Test public void tooManyArrayPropertiesIsOK() throws IOException {
   152         manyProperties(0, true, 300);
   153     }
   154 
   155     @Test public void justEnoughProperties() throws IOException {
   156         manyProperties(254, true, 0);
   157     }
   158 
   159     @Test public void justEnoughPropertiesWithArrayOne() throws IOException {
   160         manyProperties(253, true, 300);
   161     }
   162 
   163     @Test public void justEnoughPropertiesButOneArrayOne() throws IOException {
   164         manyProperties(254, false, 300);
   165     }
   166 
   167     private void manyProperties(
   168         int cnt, boolean constructorWithParams, int arrayCnt
   169     ) throws IOException {
   170         String html = "<html><body>"
   171             + "</body></html>";
   172         StringBuilder code = new StringBuilder();
   173         code.append("package x.y.z;\n"
   174             + "import net.java.html.json.Model;\n"
   175             + "import net.java.html.json.Property;\n"
   176             + "@Model(className=\"XModel\", properties={\n"
   177         );
   178         for (int i = 1; i <= cnt; i++) {
   179             code.append("  @Property(name=\"prop").append(i).append("\", ");
   180             code.append("type=int.class),\n");
   181         }
   182         for (int i = 1; i <= arrayCnt; i++) {
   183             code.append("  @Property(name=\"array").append(i).append("\", ");
   184             code.append("array=true, ");
   185             code.append("type=int.class),\n");
   186         }
   187         code.append(""
   188             + "})\n"
   189             + "class X {\n"
   190             + "    static {\n"
   191             + "      new XModel();\n"
   192             + "      new XModel("
   193         );
   194         if (constructorWithParams) {
   195             code.append("0");
   196             for (int i = 1; i < cnt; i++) {
   197                 code.append(",\n").append(i);
   198             }
   199         }
   200         code.append(");\n"
   201             + "    }\n"
   202             + "}\n"
   203         );
   204 
   205         Compile c = Compile.create(html, code.toString());
   206         assertTrue(c.getErrors().isEmpty(), "Compiles OK: " + c.getErrors());
   207     }
   208 
   209     @Test public void writeableComputedPropertyMissingWrite() throws IOException {
   210         String html = "<html><body>"
   211             + "</body></html>";
   212         String code = "package x.y.z;\n"
   213             + "import net.java.html.json.Model;\n"
   214             + "import net.java.html.json.Property;\n"
   215             + "import net.java.html.json.ComputedProperty;\n"
   216             + "@Model(className=\"XModel\", properties={\n"
   217             + "  @Property(name=\"prop\", type=int.class)\n"
   218             + "})\n"
   219             + "class X {\n"
   220             + "    static @ComputedProperty(write=\"setY\") int y(int prop) {\n"
   221             + "        return prop;\n"
   222             + "    }\n"
   223             + "}\n";
   224 
   225         Compile c = Compile.create(html, code);
   226         assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
   227         boolean ok = false;
   228         StringBuilder msgs = new StringBuilder();
   229         for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
   230             String msg = e.getMessage(Locale.ENGLISH);
   231             if (msg.contains("Cannot find setY")) {
   232                 ok = true;
   233             }
   234             msgs.append("\n").append(msg);
   235         }
   236         if (!ok) {
   237             fail("Should contain warning about non-static method:" + msgs);
   238         }
   239     }
   240 
   241     @Test public void writeableComputedPropertyWrongWriteType() throws IOException {
   242         String html = "<html><body>"
   243             + "</body></html>";
   244         String code = "package x.y.z;\n"
   245             + "import net.java.html.json.Model;\n"
   246             + "import net.java.html.json.Property;\n"
   247             + "import net.java.html.json.ComputedProperty;\n"
   248             + "@Model(className=\"XModel\", properties={\n"
   249             + "  @Property(name=\"prop\", type=int.class)\n"
   250             + "})\n"
   251             + "class X {\n"
   252             + "    static @ComputedProperty(write=\"setY\") int y(int prop) {\n"
   253             + "        return prop;\n"
   254             + "    }\n"
   255             + "    static void setY(XModel model, String prop) {\n"
   256             + "    }\n"
   257             + "}\n";
   258 
   259         Compile c = Compile.create(html, code);
   260         assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
   261         boolean ok = false;
   262         StringBuilder msgs = new StringBuilder();
   263         for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
   264             String msg = e.getMessage(Locale.ENGLISH);
   265             if (msg.contains("Write method first argument needs to be XModel and second int or Object")) {
   266                 ok = true;
   267             }
   268             msgs.append("\n").append(msg);
   269         }
   270         if (!ok) {
   271             fail("Should contain warning about non-static method:" + msgs);
   272         }
   273     }
   274 
   275     @Test public void writeableComputedPropertyReturnsVoid() throws IOException {
   276         String html = "<html><body>"
   277             + "</body></html>";
   278         String code = "package x.y.z;\n"
   279             + "import net.java.html.json.Model;\n"
   280             + "import net.java.html.json.Property;\n"
   281             + "import net.java.html.json.ComputedProperty;\n"
   282             + "@Model(className=\"XModel\", properties={\n"
   283             + "  @Property(name=\"prop\", type=int.class)\n"
   284             + "})\n"
   285             + "class X {\n"
   286             + "    static @ComputedProperty(write=\"setY\") int y(int prop) {\n"
   287             + "        return prop;\n"
   288             + "    }\n"
   289             + "    static Number setY(XModel model, int prop) {\n"
   290             + "    }\n"
   291             + "}\n";
   292 
   293         Compile c = Compile.create(html, code);
   294         assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
   295         boolean ok = false;
   296         StringBuilder msgs = new StringBuilder();
   297         for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
   298             String msg = e.getMessage(Locale.ENGLISH);
   299             if (msg.contains("Write method has to return void")) {
   300                 ok = true;
   301             }
   302             msgs.append("\n").append(msg);
   303         }
   304         if (!ok) {
   305             fail("Should contain warning about non-static method:" + msgs);
   306         }
   307     }
   308 
   309     @Test public void computedCantReturnVoid() throws IOException {
   310         String html = "<html><body>"
   311             + "</body></html>";
   312         String code = "package x.y.z;\n"
   313             + "import net.java.html.json.Model;\n"
   314             + "import net.java.html.json.Property;\n"
   315             + "import net.java.html.json.ComputedProperty;\n"
   316             + "@Model(className=\"XModel\", properties={\n"
   317             + "  @Property(name=\"prop\", type=int.class)\n"
   318             + "})\n"
   319             + "class X {\n"
   320             + "    @ComputedProperty static void y(int prop) {\n"
   321             + "    }\n"
   322             + "}\n";
   323 
   324         Compile c = Compile.create(html, code);
   325         assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
   326         boolean ok = false;
   327         StringBuilder msgs = new StringBuilder();
   328         for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
   329             String msg = e.getMessage(Locale.ENGLISH);
   330             if (msg.contains("y cannot return void")) {
   331                 ok = true;
   332             }
   333             msgs.append("\n").append(msg);
   334         }
   335         if (!ok) {
   336             fail("Should contain warning about non-static method:" + msgs);
   337         }
   338     }
   339 
   340     @Test public void computedCantReturnRunnable() throws IOException {
   341         String html = "<html><body>"
   342             + "</body></html>";
   343         String code = "package x.y.z;\n"
   344             + "import net.java.html.json.Model;\n"
   345             + "import net.java.html.json.Property;\n"
   346             + "import net.java.html.json.ComputedProperty;\n"
   347             + "@Model(className=\"XModel\", properties={\n"
   348             + "  @Property(name=\"prop\", type=int.class)\n"
   349             + "})\n"
   350             + "class X {\n"
   351             + "    @ComputedProperty static Runnable y(int prop) {\n"
   352             + "       return null;\n"
   353             + "    }\n"
   354             + "}\n";
   355 
   356         Compile c = Compile.create(html, code);
   357         assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
   358         boolean ok = false;
   359         StringBuilder msgs = new StringBuilder();
   360         for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
   361             String msg = e.getMessage(Locale.ENGLISH);
   362             if (msg.contains("y cannot return java.lang.Runnable")) {
   363                 ok = true;
   364             }
   365             msgs.append("\n").append(msg);
   366         }
   367         if (!ok) {
   368             fail("Should contain warning about non-static method:" + msgs);
   369         }
   370     }
   371 
   372     @Test public void canWeCompileWithJDK1_5SourceLevel() throws IOException {
   373         String html = "<html><body>"
   374             + "</body></html>";
   375         String code = "package x.y.z;\n"
   376             + "import net.java.html.json.Model;\n"
   377             + "import net.java.html.json.Property;\n"
   378             + "import net.java.html.json.ComputedProperty;\n"
   379             + "@Model(className=\"XModel\", properties={\n"
   380             + "  @Property(name=\"prop\", type=long.class)\n"
   381             + "})\n"
   382             + "class X {\n"
   383             + "  @ComputedProperty static double derived(long prop) { return prop; }"
   384             + "}\n";
   385 
   386         Compile c = Compile.create(html, code, "1.5");
   387         assertTrue(c.getErrors().isEmpty(), "No errors: " + c.getErrors());
   388     }
   389     
   390     @Test public void instanceNeedsDefaultConstructor() throws IOException {
   391         String html = "<html><body>"
   392             + "</body></html>";
   393         String code = "package x.y.z;\n"
   394             + "import net.java.html.json.Model;\n"
   395             + "import net.java.html.json.Property;\n"
   396             + "import net.java.html.json.ComputedProperty;\n"
   397             + "@Model(className=\"XModel\", instance=true, properties={\n"
   398             + "  @Property(name=\"prop\", type=long.class)\n"
   399             + "})\n"
   400             + "class X {\n"
   401             + "  X(int x) {}\n"
   402             + "}\n";
   403 
   404         Compile c = Compile.create(html, code);
   405         c.assertError("Needs non-private default constructor when instance=true");
   406     }
   407     
   408     @Test public void instanceNeedsNonPrivateConstructor() throws IOException {
   409         String html = "<html><body>"
   410             + "</body></html>";
   411         String code = "package x.y.z;\n"
   412             + "import net.java.html.json.Model;\n"
   413             + "import net.java.html.json.Property;\n"
   414             + "import net.java.html.json.ComputedProperty;\n"
   415             + "@Model(className=\"XModel\", instance=true, properties={\n"
   416             + "  @Property(name=\"prop\", type=long.class)\n"
   417             + "})\n"
   418             + "class X {\n"
   419             + "  private X() {}\n"
   420             + "}\n";
   421 
   422         Compile c = Compile.create(html, code);
   423         c.assertError("Needs non-private default constructor when instance=true");
   424     }
   425 
   426     @Test public void instanceNoConstructorIsOK() throws IOException {
   427         String html = "<html><body>"
   428             + "</body></html>";
   429         String code = "package x.y.z;\n"
   430             + "import net.java.html.json.Model;\n"
   431             + "import net.java.html.json.Property;\n"
   432             + "import net.java.html.json.ComputedProperty;\n"
   433             + "@Model(className=\"XModel\", instance=true, properties={\n"
   434             + "  @Property(name=\"prop\", type=long.class)\n"
   435             + "})\n"
   436             + "class X {\n"
   437             + "}\n";
   438 
   439         Compile c = Compile.create(html, code);
   440         c.assertNoErrors();
   441     }
   442 
   443     @Test public void putNeedsDataArgument() throws Exception {
   444         needsAnArg("PUT");
   445     }
   446 
   447     @Test public void postNeedsDataArgument() throws Exception {
   448         needsAnArg("POST");
   449     }
   450 
   451     private void needsAnArg(String method) throws Exception {
   452         String html = "<html><body>"
   453             + "</body></html>";
   454         String code = "package x.y.z;\n"
   455             + "import net.java.html.json.Model;\n"
   456             + "import net.java.html.json.Property;\n"
   457             + "import net.java.html.json.OnReceive;\n"
   458             + "@Model(className=\"XModel\", properties={\n"
   459             + "  @Property(name=\"prop\", type=long.class)\n"
   460             + "})\n"
   461             + "class X {\n"
   462             + "  @Model(className=\"PQ\", properties={})\n"
   463             + "  class PImpl {\n"
   464             + "  }\n"
   465             + "  @OnReceive(method=\"" + method + "\", url=\"whereever\")\n"
   466             + "  static void obtained(XModel m, PQ p) { }\n"
   467             + "}\n";
   468 
   469         Compile c = Compile.create(html, code);
   470         assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
   471         for (Diagnostic<? extends JavaFileObject> diagnostic : c.getErrors()) {
   472             String msg = diagnostic.getMessage(Locale.ENGLISH);
   473             if (msg.contains("specify a data()")) {
   474                 return;
   475             }
   476         }
   477         fail("Needs an error message about missing data():\n" + c.getErrors());
   478 
   479     }
   480 
   481 
   482     @Test public void jsonNeedsToUseGet () throws Exception {
   483         String html = "<html><body>"
   484             + "</body></html>";
   485         String code = "package x.y.z;\n"
   486             + "import net.java.html.json.Model;\n"
   487             + "import net.java.html.json.Property;\n"
   488             + "import net.java.html.json.OnReceive;\n"
   489             + "@Model(className=\"XModel\", properties={\n"
   490             + "  @Property(name=\"prop\", type=long.class)\n"
   491             + "})\n"
   492             + "class X {\n"
   493             + "  @Model(className=\"PQ\", properties={})\n"
   494             + "  class PImpl {\n"
   495             + "  }\n"
   496             + "  @OnReceive(method=\"POST\", jsonp=\"callback\", url=\"whereever\")\n"
   497             + "  static void obtained(XModel m, PQ p) { }\n"
   498             + "}\n";
   499 
   500         Compile c = Compile.create(html, code);
   501         assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
   502         for (Diagnostic<? extends JavaFileObject> diagnostic : c.getErrors()) {
   503             String msg = diagnostic.getMessage(Locale.ENGLISH);
   504             if (msg.contains("JSONP works only with GET")) {
   505                 return;
   506             }
   507         }
   508         fail("Needs an error message about wrong method:\n" + c.getErrors());
   509 
   510     }
   511 
   512     @Test public void noHeadersForWebSockets() throws Exception {
   513         String html = "<html><body>"
   514             + "</body></html>";
   515         String code = "package x.y.z;\n"
   516             + "import net.java.html.json.Model;\n"
   517             + "import net.java.html.json.Property;\n"
   518             + "import net.java.html.json.OnReceive;\n"
   519             + "@Model(className=\"XModel\", properties={\n"
   520             + "  @Property(name=\"prop\", type=long.class)\n"
   521             + "})\n"
   522             + "class X {\n"
   523             + "  @Model(className=\"PQ\", properties={})\n"
   524             + "  class PImpl {\n"
   525             + "  }\n"
   526             + "  @OnReceive(method=\"WebSocket\", data = PQ.class, headers=\"SomeHeader: {some}\", url=\"whereever\")\n"
   527             + "  static void obtained(XModel m, PQ p) { }\n"
   528             + "}\n";
   529 
   530         Compile c = Compile.create(html, code);
   531         assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
   532         for (Diagnostic<? extends JavaFileObject> diagnostic : c.getErrors()) {
   533             String msg = diagnostic.getMessage(Locale.ENGLISH);
   534             if (msg.contains("WebSocket spec does not support headers")) {
   535                 return;
   536             }
   537         }
   538         fail("Needs an error message about headers:\n" + c.getErrors());
   539 
   540     }
   541 
   542     @Test public void webSocketsWithoutDataIsError() throws Exception {
   543         String html = "<html><body>"
   544             + "</body></html>";
   545         String code = "package x.y.z;\n"
   546             + "import net.java.html.json.Model;\n"
   547             + "import net.java.html.json.Property;\n"
   548             + "import net.java.html.json.OnReceive;\n"
   549             + "@Model(className=\"XModel\", properties={\n"
   550             + "  @Property(name=\"prop\", type=long.class)\n"
   551             + "})\n"
   552             + "class X {\n"
   553             + "  @Model(className=\"PQ\", properties={})\n"
   554             + "  class PImpl {\n"
   555             + "  }\n"
   556             + "  @OnReceive(method=\"WebSocket\", url=\"whereever\")\n"
   557             + "  static void obtained(XModel m, PQ p) { }\n"
   558             + "}\n";
   559 
   560         Compile c = Compile.create(html, code);
   561         assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
   562         for (Diagnostic<? extends JavaFileObject> diagnostic : c.getErrors()) {
   563             String msg = diagnostic.getMessage(Locale.ENGLISH);
   564             if (msg.contains("eeds to specify a data()")) {
   565                 return;
   566             }
   567         }
   568         fail("Needs data attribute :\n" + c.getErrors());
   569     }
   570 
   571     @Test public void noNewLinesInHeaderLines() throws Exception {
   572         String html = "<html><body>"
   573             + "</body></html>";
   574         String code = "package x.y.z;\n"
   575             + "import net.java.html.json.Model;\n"
   576             + "import net.java.html.json.Property;\n"
   577             + "import net.java.html.json.OnReceive;\n"
   578             + "@Model(className=\"XModel\", properties={\n"
   579             + "  @Property(name=\"prop\", type=long.class)\n"
   580             + "})\n"
   581             + "class X {\n"
   582             + "  @Model(className=\"PQ\", properties={})\n"
   583             + "  class PImpl {\n"
   584             + "  }\n"
   585             + "  @OnReceive(headers=\"SomeHeader\\n: {some}\", url=\"whereever\")\n"
   586             + "  static void obtained(XModel m, PQ p) { }\n"
   587             + "}\n";
   588 
   589         Compile c = Compile.create(html, code);
   590         assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
   591         for (Diagnostic<? extends JavaFileObject> diagnostic : c.getErrors()) {
   592             String msg = diagnostic.getMessage(Locale.ENGLISH);
   593             if (msg.contains("Header line cannot contain line separator")) {
   594                 return;
   595             }
   596         }
   597         fail("Needs an error message about headers:\n" + c.getErrors());
   598 
   599     }
   600 
   601     @Test public void noReturnInHeaderLines() throws Exception {
   602         String html = "<html><body>"
   603             + "</body></html>";
   604         String code = "package x.y.z;\n"
   605             + "import net.java.html.json.Model;\n"
   606             + "import net.java.html.json.Property;\n"
   607             + "import net.java.html.json.OnReceive;\n"
   608             + "@Model(className=\"XModel\", properties={\n"
   609             + "  @Property(name=\"prop\", type=long.class)\n"
   610             + "})\n"
   611             + "class X {\n"
   612             + "  @Model(className=\"PQ\", properties={})\n"
   613             + "  class PImpl {\n"
   614             + "  }\n"
   615             + "  @OnReceive(headers=\"Some\\rHeader: {some}\", url=\"whereever\")\n"
   616             + "  static void obtained(XModel m, PQ p) { }\n"
   617             + "}\n";
   618 
   619         Compile c = Compile.create(html, code);
   620         assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
   621         for (Diagnostic<? extends JavaFileObject> diagnostic : c.getErrors()) {
   622             String msg = diagnostic.getMessage(Locale.ENGLISH);
   623             if (msg.contains("Header line cannot contain line separator")) {
   624                 return;
   625             }
   626         }
   627         fail("Needs an error message about headers:\n" + c.getErrors());
   628 
   629     }
   630 
   631     @Test public void onErrorHasToExist() throws IOException {
   632         Compile res = Compile.create("", "package x;\n"
   633             + "@net.java.html.json.Model(className=\"MyModel\", properties= {\n"
   634             + "  @net.java.html.json.Property(name=\"x\", type=String.class)\n"
   635             + "})\n"
   636             + "class UseOnReceive {\n"
   637             + "  @net.java.html.json.OnReceive(url=\"http://nowhere.com\", onError=\"doesNotExist\")\n"
   638             + "  static void onMessage(MyModel model, String value) {\n"
   639             + "  }\n"
   640             + "}\n"
   641         );
   642         res.assertErrors();
   643         res.assertError("not find doesNotExist");
   644     }
   645 
   646     @Test public void usingListIsOK() throws IOException {
   647         Compile res = Compile.create("", "package x;\n"
   648             + "@net.java.html.json.Model(className=\"MyModel\", properties= {\n"
   649             + "  @net.java.html.json.Property(name=\"x\", type=String.class)\n"
   650             + "})\n"
   651             + "class UseOnReceive {\n"
   652             + "  @net.java.html.json.OnReceive(url=\"http://nowhere.com\")\n"
   653             + "  static void onMessage(MyModel model, java.util.List<MyData> value) {\n"
   654             + "  }\n"
   655             + "\n"
   656             + "  @net.java.html.json.Model(className=\"MyData\", properties={\n"
   657             + "  })\n"
   658             + "  static class MyDataModel {\n"
   659             + "  }\n"
   660             + "}\n"
   661         );
   662         res.assertNoErrors();
   663     }
   664 
   665     @Test public void functionAndPropertyCollide() throws IOException {
   666         Compile res = Compile.create("", "package x;\n"
   667             + "@net.java.html.json.Model(className=\"MyModel\", properties= {\n"
   668             + "  @net.java.html.json.Property(name=\"x\", type=String.class)\n"
   669             + "})\n"
   670             + "class Collision {\n"
   671             + "  @net.java.html.json.Function\n"
   672             + "  static void x(MyModel model, String value) {\n"
   673             + "  }\n"
   674             + "}\n"
   675         );
   676         res.assertErrors();
   677         res.assertError("cannot have the name");
   678     }
   679 
   680     @Test public void twoPropertiesCollide() throws IOException {
   681         Compile res = Compile.create("", "package x;\n"
   682             + "@net.java.html.json.Model(className=\"MyModel\", properties= {\n"
   683             + "  @net.java.html.json.Property(name=\"x\", type=String.class),\n"
   684             + "  @net.java.html.json.Property(name=\"x\", type=int.class)\n"
   685             + "})\n"
   686             + "class Collision {\n"
   687             + "}\n"
   688         );
   689         res.assertErrors();
   690         res.assertError("Cannot have the name");
   691     }
   692 
   693     @Test public void propertyAndComputedOneCollide() throws IOException {
   694         Compile res = Compile.create("", "package x;\n"
   695             + "@net.java.html.json.Model(className=\"MyModel\", properties= {\n"
   696             + "  @net.java.html.json.Property(name=\"x\", type=String.class),\n"
   697             + "})\n"
   698             + "class Collision {\n"
   699             + "  @net.java.html.json.ComputedProperty static int x(String x) {\n"
   700             + "    return x.length();\n"
   701             + "  }\n"
   702             + "}\n"
   703         );
   704         res.assertErrors();
   705         res.assertError("Cannot have the name");
   706     }
   707 
   708     @Test public void onWebSocketJustTwoArgs() throws IOException {
   709         Compile res = Compile.create("", "package x;\n"
   710             + "@net.java.html.json.Model(className=\"MyModel\", properties= {\n"
   711             + "  @net.java.html.json.Property(name=\"x\", type=String.class)\n"
   712             + "})\n"
   713             + "class UseOnReceive {\n"
   714             + "  @net.java.html.json.OnReceive(url=\"http://nowhere.com\", method=\"WebSocket\", data=String.class)\n"
   715             + "  static void onMessage(MyModel model, String value, int arg) {\n"
   716             + "  }\n"
   717             + "}\n"
   718         );
   719         res.assertErrors();
   720         res.assertError("only have two arg");
   721     }
   722 
   723     @Test public void onErrorWouldHaveToBeStatic() throws IOException {
   724         Compile res = Compile.create("", "package x;\n"
   725             + "@net.java.html.json.Model(className=\"MyModel\", properties= {\n"
   726             + "  @net.java.html.json.Property(name=\"x\", type=String.class)\n"
   727             + "})\n"
   728             + "class UseOnReceive {\n"
   729             + "  @net.java.html.json.OnReceive(url=\"http://nowhere.com\", onError=\"notStatic\")\n"
   730             + "  static void onMessage(MyModel model, String value) {\n"
   731             + "  }\n"
   732             + "  void notStatic(Exception e) {}\n"
   733             + "}\n"
   734         );
   735         res.assertErrors();
   736         res.assertError("have to be static");
   737     }
   738 
   739     @Test public void onErrorMustAcceptExceptionArgument() throws IOException {
   740         Compile res = Compile.create("", "package x;\n"
   741             + "@net.java.html.json.Model(className=\"MyModel\", properties= {\n"
   742             + "  @net.java.html.json.Property(name=\"x\", type=String.class)\n"
   743             + "})\n"
   744             + "class UseOnReceive {\n"
   745             + "  @net.java.html.json.OnReceive(url=\"http://nowhere.com\", onError=\"subclass\")\n"
   746             + "  static void onMessage(MyModel model, String value) {\n"
   747             + "  }\n"
   748             + "  static void subclass(java.io.IOException e) {}\n"
   749             + "}\n"
   750         );
   751         res.assertErrors();
   752         res.assertError("Error method first argument needs to be MyModel and second Exception");
   753     }
   754 }