During the API review process (bug 246133) the reviewers decided that in order to include html4j to NetBeans Platform, we need to stop using org.apidesign namespace and switch to NetBeans one. Repackaging all SPI packages into org.netbeans.html.smthng.spi.
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
6 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7 * Other names may be trademarks of their respective owners.
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]"
29 * The Original Software is NetBeans. The Initial Developer of the Original
30 * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
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.
44 package net.java.html.json.tests;
46 import java.util.ArrayList;
47 import java.util.List;
48 import java.util.Random;
49 import net.java.html.BrwsrCtx;
50 import net.java.html.json.ComputedProperty;
51 import net.java.html.json.Function;
52 import net.java.html.json.Model;
53 import net.java.html.json.ModelOperation;
54 import net.java.html.json.Models;
55 import net.java.html.json.Property;
56 import org.netbeans.html.json.tck.KOTest;
58 /** Tests model of a mine field and its behavior in the browser.
60 @Model(className = "Mines", properties = {
61 @Property(name = "state", type = MinesTest.GameState.class),
62 @Property(name = "rows", type = Row.class, array = true),
64 public final class MinesTest {
66 @KOTest public void paintTheGridOnClick() throws Throwable {
68 BrwsrCtx ctx = Utils.newContext(MinesTest.class);
69 Object exp = Utils.exposeHTML(MinesTest.class,
70 " <button id='init' data-bind='click: normalSize'></button>\n" +
72 " <tbody id='table'>\n" +
73 " <!-- ko foreach: rows -->\n" +
75 " <!-- ko foreach: columns -->\n" +
76 " <td data-bind='css: style' >\n" +
77 " <div data-bind='text: html'></div>\n" +
86 m = Models.bind(new Mines(), ctx);
88 int cnt = Utils.countChildren(MinesTest.class, "table");
89 assert cnt == 0 : "Table is empty: " + cnt;
90 scheduleClick("init", 100);
94 int cnt = Utils.countChildren(MinesTest.class, "table");
96 throw new InterruptedException();
98 assert cnt == 10 : "There is ten rows in the table now: " + cnt;
100 Utils.exposeHTML(MinesTest.class, "");
103 @KOTest public void countAround() throws Exception {
104 Mines mines = new Mines();
106 mines.getRows().get(0).getColumns().get(0).setMine(true);
107 mines.getRows().get(1).getColumns().get(0).setMine(true);
108 mines.getRows().get(0).getColumns().get(1).setMine(true);
110 int cnt = around(mines, 1, 1);
111 assert cnt == 3 : "There are three mines around. Was: " + cnt;
114 private static void scheduleClick(String id, int delay) throws Exception {
115 String s = "var id = arguments[0]; var delay = arguments[1];"
116 + "var e = window.document.getElementById(id);\n "
117 + "var f = function() {;\n "
118 + " var ev = window.document.createEvent('MouseEvents');\n "
119 + " ev.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);\n "
120 + " e.dispatchEvent(ev);\n"
122 + "window.setTimeout(f, delay);";
129 IN_PROGRESS, WON, LOST;
132 @Model(className = "Row", properties = {
133 @Property(name = "columns", type = Square.class, array = true)
135 static class RowModel {
138 @Model(className = "Square", properties = {
139 @Property(name = "state", type = SquareType.class),
140 @Property(name = "mine", type = boolean.class)
142 static class SquareModel {
143 @ComputedProperty static String html(SquareType state) {
144 if (state == null) return " ";
146 case EXPLOSION: return "✗";
147 case UNKNOWN: return " ";
148 case DISCOVERED: return "✔";
149 case N_0: return " ";
151 return "ɸ" + (state.ordinal() - 1);
154 @ComputedProperty static String style(SquareType state) {
155 return state == null ? null : state.toString();
160 N_0, N_1, N_2, N_3, N_4, N_5, N_6, N_7, N_8,
161 UNKNOWN, EXPLOSION, DISCOVERED;
163 final boolean isVisible() {
164 return name().startsWith("N_");
167 final SquareType moreBombsAround() {
175 return values()[ordinal() + 1];
179 @ComputedProperty static boolean fieldShowing(GameState state) {
180 return state != null;
183 @Function static void normalSize(Mines m) {
187 @ModelOperation static void init(Mines model, int width, int height, int mines) {
188 List<Row> rows = new ArrayList<Row>(height);
189 for (int y = 0; y < height; y++) {
190 Square[] columns = new Square[width];
191 for (int x = 0; x < width; x++) {
192 columns[x] = new Square(SquareType.UNKNOWN, false);
194 rows.add(new Row(columns));
197 Random r = new Random();
199 int x = r.nextInt(width);
200 int y = r.nextInt(height);
201 final Square s = rows.get(y).getColumns().get(x);
209 model.setState(GameState.IN_PROGRESS);
210 model.getRows().clear();
211 model.getRows().addAll(rows);
214 @ModelOperation static void computeMines(Mines model) {
215 List<Integer> xBombs = new ArrayList<Integer>();
216 List<Integer> yBombs = new ArrayList<Integer>();
217 final List<Row> rows = model.getRows();
218 boolean emptyHidden = false;
219 SquareType[][] arr = new SquareType[rows.size()][];
220 for (int y = 0; y < rows.size(); y++) {
221 final List<Square> columns = rows.get(y).getColumns();
222 arr[y] = new SquareType[columns.size()];
223 for (int x = 0; x < columns.size(); x++) {
224 Square sq = columns.get(x);
229 if (sq.getState().isVisible()) {
230 arr[y][x] = SquareType.N_0;
238 for (int i = 0; i < xBombs.size(); i++) {
239 int x = xBombs.get(i);
240 int y = yBombs.get(i);
242 incrementAround(arr, x, y);
244 for (int y = 0; y < rows.size(); y++) {
245 final List<Square> columns = rows.get(y).getColumns();
246 for (int x = 0; x < columns.size(); x++) {
247 Square sq = columns.get(x);
248 final SquareType newState = arr[y][x];
249 if (newState != null && newState != sq.getState()) {
250 sq.setState(newState);
256 model.setState(GameState.WON);
257 showAllBombs(model, SquareType.DISCOVERED);
261 private static void incrementAround(SquareType[][] arr, int x, int y) {
262 incrementAt(arr, x - 1, y - 1);
263 incrementAt(arr, x - 1, y);
264 incrementAt(arr, x - 1, y + 1);
266 incrementAt(arr, x + 1, y - 1);
267 incrementAt(arr, x + 1, y);
268 incrementAt(arr, x + 1, y + 1);
270 incrementAt(arr, x, y - 1);
271 incrementAt(arr, x, y + 1);
274 private static void incrementAt(SquareType[][] arr, int x, int y) {
275 if (y >= 0 && y < arr.length) {
276 SquareType[] r = arr[y];
277 if (x >= 0 && x < r.length) {
278 SquareType sq = r[x];
280 r[x] = sq.moreBombsAround();
286 static void showAllBombs(Mines model, SquareType state) {
287 for (Row row : model.getRows()) {
288 for (Square square : row.getColumns()) {
289 if (square.isMine()) {
290 square.setState(state);
296 private static void expandKnown(Mines model, Square data) {
297 final List<Row> rows = model.getRows();
298 for (int y = 0; y < rows.size(); y++) {
299 final List<Square> columns = rows.get(y).getColumns();
300 for (int x = 0; x < columns.size(); x++) {
301 Square sq = columns.get(x);
303 expandKnown(model, x, y);
309 private static void expandKnown(Mines model, int x , int y) {
310 if (y < 0 || y >= model.getRows().size()) {
313 final List<Square> columns = model.getRows().get(y).getColumns();
314 if (x < 0 || x >= columns.size()) {
317 final Square sq = columns.get(x);
318 if (sq.getState() == SquareType.UNKNOWN) {
319 int around = around(model, x, y);
320 final SquareType t = SquareType.valueOf("N_" + around);
322 if (sq.getState() == SquareType.N_0) {
323 expandKnown(model, x - 1, y - 1);
324 expandKnown(model, x - 1, y);
325 expandKnown(model, x - 1, y + 1);
326 expandKnown(model, x , y - 1);
327 expandKnown(model, x, y + 1);
328 expandKnown(model, x + 1, y - 1);
329 expandKnown(model, x + 1, y);
330 expandKnown(model, x + 1, y + 1);
334 private static int around(Mines model, int x, int y) {
335 return minesAt(model, x - 1, y - 1)
336 + minesAt(model, x - 1, y)
337 + minesAt(model, x - 1, y + 1)
338 + minesAt(model, x, y - 1)
339 + minesAt(model, x, y + 1)
340 + minesAt(model, x + 1, y - 1)
341 + minesAt(model, x + 1, y)
342 + minesAt(model, x + 1, y + 1);
345 private static int minesAt(Mines model, int x, int y) {
346 if (y < 0 || y >= model.getRows().size()) {
349 final List<Square> columns = model.getRows().get(y).getColumns();
350 if (x < 0 || x >= columns.size()) {
353 Square sq = columns.get(x);
354 return sq.isMine() ? 1 : 0;