Path: blob/master/test/jdk/javax/management/query/QueryExpStringTest.java
41152 views
/*1* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 488601126* @summary Test that QueryExp.toString() is reversible27* @author Eamonn McManus28*29* @run clean QueryExpStringTest30* @run build QueryExpStringTest31* @run main QueryExpStringTest32*/3334import java.util.*;35import javax.management.*;3637public class QueryExpStringTest {3839private static final ValueExp40attr = Query.attr("attr"),41qattr = Query.attr("className", "attr"),42aa = Query.attr("A"),43bb = Query.attr("B"),44cc = Query.attr("C"),45dd = Query.attr("D"),46zero = Query.value(0),47classattr = Query.classattr(),48simpleString = Query.value("simpleString"),49complexString = Query.value("a'b\\'\""),50intValue = Query.value(12345678),51integerValue = Query.value(new Integer(12345678)),52longValue = Query.value(12345678L),53floatValue = Query.value(2.5f),54doubleValue = Query.value(2.5d),55booleanValue = Query.value(true),56plusValue = Query.plus(intValue, integerValue),57timesValue = Query.times(doubleValue, floatValue),58minusValue = Query.minus(floatValue, doubleValue),59divValue = Query.div(doubleValue, floatValue);6061private static final QueryExp62gt = Query.gt(intValue, floatValue),63geq = Query.geq(intValue, floatValue),64leq = Query.leq(intValue, floatValue),65lt = Query.lt(intValue, floatValue),66eq = Query.eq(intValue, floatValue),67between = Query.between(intValue, floatValue, doubleValue),68match = Query.match((AttributeValueExp) attr,69(StringValueExp) simpleString),70initial = Query.initialSubString((AttributeValueExp) attr,71(StringValueExp) simpleString),72initialStar = Query.initialSubString((AttributeValueExp) attr,73Query.value("*")),74initialPercent = Query.initialSubString((AttributeValueExp) attr,75Query.value("%")),76any = Query.anySubString((AttributeValueExp) attr,77(StringValueExp) simpleString),78anyStar = Query.anySubString((AttributeValueExp) attr,79Query.value("*")),80anyPercent = Query.anySubString((AttributeValueExp) attr,81Query.value("%")),82ffinal = Query.finalSubString((AttributeValueExp) attr,83(StringValueExp) simpleString),84finalMagic = Query.finalSubString((AttributeValueExp) attr,85Query.value("?*[\\")),86in = Query.in(intValue, new ValueExp[] {intValue, floatValue}),87and = Query.and(gt, lt),88or = Query.or(gt, lt),89not = Query.not(gt),90aPlusB_PlusC = Query.gt(Query.plus(Query.plus(aa, bb), cc), zero),91aPlus_BPlusC = Query.gt(Query.plus(aa, Query.plus(bb, cc)), zero);9293// Commented-out tests below require change to implementation9495private static final Object tests[] = {96attr, "attr",97// qattr, "className.attr",98// Preceding form now appears as className#attr, an incompatible change99// which we don't mind much because nobody uses the two-arg Query.attr.100classattr, "Class",101simpleString, "'simpleString'",102complexString, "'a''b\\\''\"'",103intValue, "12345678",104integerValue, "12345678",105longValue, "12345678",106floatValue, "2.5",107doubleValue, "2.5",108booleanValue, "true",109plusValue, "12345678 + 12345678",110timesValue, "2.5 * 2.5",111minusValue, "2.5 - 2.5",112divValue, "2.5 / 2.5",113gt, "(12345678) > (2.5)",114geq, "(12345678) >= (2.5)",115leq, "(12345678) <= (2.5)",116lt, "(12345678) < (2.5)",117eq, "(12345678) = (2.5)",118between, "(12345678) between (2.5) and (2.5)",119match, "attr like 'simpleString'",120initial, "attr like 'simpleString*'",121initialStar, "attr like '\\**'",122initialPercent, "attr like '%*'",123any, "attr like '*simpleString*'",124anyStar, "attr like '*\\**'",125anyPercent, "attr like '*%*'",126ffinal, "attr like '*simpleString'",127finalMagic, "attr like '*\\?\\*\\[\\\\'",128in, "12345678 in (12345678, 2.5)",129and, "((12345678) > (2.5)) and ((12345678) < (2.5))",130or, "((12345678) > (2.5)) or ((12345678) < (2.5))",131not, "not ((12345678) > (2.5))",132aPlusB_PlusC, "(A + B + C) > (0)",133// aPlus_BPlusC, "(A + (B + C)) > (0)",134};135136public static void main(String[] args) throws Exception {137System.out.println("Testing QueryExp.toString()");138139boolean ok = true;140141for (int i = 0; i < tests.length; i += 2) {142String testString = tests[i].toString();143String expected = (String) tests[i + 1];144if (expected.equals(testString))145System.out.println("OK: " + expected);146else {147System.err.println("Expected: {" + expected + "}; got: {" +148testString + "}");149ok = false;150}151152try {153Object parsed;154String[] expectedref = new String[] {expected};155if (tests[i] instanceof ValueExp)156parsed = parseExp(expectedref);157else158parsed = parseQuery(expectedref);159if (expectedref[0].length() > 0)160throw new Exception("Junk after parse: " + expectedref[0]);161String parsedString = parsed.toString();162if (parsedString.equals(expected))163System.out.println("OK: parsed " + parsedString);164else {165System.err.println("Parse differs: expected: {" +166expected + "}; got: {" +167parsedString + "}");168ok = false;169}170} catch (Exception e) {171System.err.println("Parse got exception: {" + expected +172"}: " + e);173ok = false;174}175}176177if (ok)178System.out.println("Test passed");179else {180System.out.println("TEST FAILED");181System.exit(1);182}183}184185private static QueryExp parseQuery(String[] ss) throws Exception {186if (skip(ss, "("))187return parseQueryAfterParen(ss);188189if (skip(ss, "not (")) {190QueryExp not = parseQuery(ss);191if (!skip(ss, ")"))192throw new Exception("Expected ) after not (...");193return Query.not(not);194}195196ValueExp exp = parseExp(ss);197198if (skip(ss, " like ")) {199ValueExp pat = parseExp(ss);200if (!(exp instanceof AttributeValueExp &&201pat instanceof StringValueExp)) {202throw new Exception("Expected types `attr like string': " +203exp + " like " + pat);204}205StringValueExp spat = (StringValueExp) pat;206return Query.match((AttributeValueExp) exp, spat);207}208209if (skip(ss, " in (")) {210List values = new ArrayList();211if (!skip(ss, ")")) {212do {213values.add(parseExp(ss));214} while (skip(ss, ", "));215if (!skip(ss, ")"))216throw new Exception("Expected ) after in (...");217}218return Query.in(exp, (ValueExp[]) values.toArray(new ValueExp[0]));219}220221throw new Exception("Expected in or like after expression");222}223224private static QueryExp parseQueryAfterParen(String[] ss)225throws Exception {226/* This is very ugly. We might have "(q1) and (q2)" here, or227we might have "(e1) < (e2)". Since the syntax for a query228(q1) is not the same as for an expression (e1), but can229begin with one, we try to parse the query, and if we get an230exception we then try to parse an expression. It's a hacky231kind of look-ahead. */232String start = ss[0];233try {234QueryExp lhs = parseQuery(ss);235QueryExp result;236237if (skip(ss, ") and ("))238result = Query.and(lhs, parseQuery(ss));239else if (skip(ss, ") or ("))240result = Query.or(lhs, parseQuery(ss));241else242throw new Exception("Expected `) and/or ('");243if (!skip(ss, ")"))244throw new Exception("Expected `)' after subquery");245return result;246} catch (Exception e) {247ss[0] = start;248ValueExp lhs = parseExp(ss);249if (!skip(ss, ") "))250throw new Exception("Expected `) ' after subexpression: " + ss[0]);251String op = scanWord(ss);252if (!skip(ss, " ("))253throw new Exception("Expected ` (' after `" + op + "'");254ValueExp rhs = parseExp(ss);255if (!skip(ss, ")"))256throw new Exception("Expected `)' after subexpression");257if (op.equals("="))258return Query.eq(lhs, rhs);259if (op.equals("<"))260return Query.lt(lhs, rhs);261if (op.equals(">"))262return Query.gt(lhs, rhs);263if (op.equals("<="))264return Query.leq(lhs, rhs);265if (op.equals(">="))266return Query.geq(lhs, rhs);267if (!op.equals("between"))268throw new Exception("Unknown operator `" + op + "'");269if (!skip(ss, " and ("))270throw new Exception("Expected ` and (' after between");271ValueExp high = parseExp(ss);272if (!skip(ss, ")"))273throw new Exception("Expected `)' after subexpression");274return Query.between(lhs, rhs, high);275}276}277278private static ValueExp parseExp(String[] ss) throws Exception {279ValueExp lhs = parsePrimary(ss);280281while (true) {282/* Look ahead to see if we have an arithmetic operator. */283String back = ss[0];284if (!skip(ss, " "))285return lhs;286if (ss[0].equals("") || "+-*/".indexOf(ss[0].charAt(0)) < 0) {287ss[0] = back;288return lhs;289}290291final String op = scanWord(ss);292if (op.length() != 1)293throw new Exception("Expected arithmetic operator after space");294if ("+-*/".indexOf(op) < 0)295throw new Exception("Unknown arithmetic operator: " + op);296if (!skip(ss, " "))297throw new Exception("Expected space after arithmetic operator");298ValueExp rhs = parsePrimary(ss);299switch (op.charAt(0)) {300case '+': lhs = Query.plus(lhs, rhs); break;301case '-': lhs = Query.minus(lhs, rhs); break;302case '*': lhs = Query.times(lhs, rhs); break;303case '/': lhs = Query.div(lhs, rhs); break;304default: throw new Exception("Can't happen: " + op.charAt(0));305}306}307}308309private static ValueExp parsePrimary(String[] ss) throws Exception {310String s = ss[0];311312if (s.length() == 0)313throw new Exception("Empty string found, expression expected");314315char first = s.charAt(0);316317if (first == ' ')318throw new Exception("Space found, expression expected");319320if (first == '-' || Character.isDigit(first))321return parseNumberExp(ss);322323if (first == '\'')324return parseString(ss);325326if (matchWord(ss, "true"))327return Query.value(true);328329if (matchWord(ss, "false"))330return Query.value(false);331332if (matchWord(ss, "Class"))333return Query.classattr();334335String word = scanWord(ss);336int lastDot = word.lastIndexOf('.');337if (lastDot < 0)338return Query.attr(word);339else340return Query.attr(word.substring(0, lastDot),341word.substring(lastDot + 1));342}343344private static String scanWord(String[] ss) throws Exception {345String s = ss[0];346int space = s.indexOf(' ');347int rpar = s.indexOf(')');348if (space < 0 && rpar < 0) {349ss[0] = "";350return s;351}352int stop;353if (space >= 0 && rpar >= 0) // string has both space and ), stop at first354stop = Math.min(space, rpar);355else // string has only one, stop at it356stop = Math.max(space, rpar);357String word = s.substring(0, stop);358ss[0] = s.substring(stop);359return word;360}361362private static boolean matchWord(String[] ss, String word)363throws Exception {364String s = ss[0];365if (s.startsWith(word)) {366int len = word.length();367if (s.length() == len || s.charAt(len) == ' '368|| s.charAt(len) == ')') {369ss[0] = s.substring(len);370return true;371}372}373return false;374}375376private static ValueExp parseNumberExp(String[] ss) throws Exception {377String s = ss[0];378int len = s.length();379boolean isFloat = false;380int i;381for (i = 0; i < len; i++) {382char c = s.charAt(i);383if (Character.isDigit(c) || c == '-' || c == '+')384continue;385if (c == '.' || c == 'e' || c == 'E') {386isFloat = true;387continue;388}389break;390}391ss[0] = s.substring(i);392s = s.substring(0, i);393if (isFloat)394return Query.value(Double.parseDouble(s));395else396return Query.value(Long.parseLong(s));397}398399private static ValueExp parseString(String[] ss) throws Exception {400if (!skip(ss, "'"))401throw new Exception("Expected ' at start of string");402String s = ss[0];403int len = s.length();404StringBuffer buf = new StringBuffer();405int i;406for (i = 0; i < len; i++) {407char c = s.charAt(i);408if (c == '\'') {409++i;410if (i >= len || s.charAt(i) != '\'') {411ss[0] = s.substring(i);412return Query.value(buf.toString());413}414}415buf.append(c);416}417throw new Exception("No closing ' at end of string");418}419420private static boolean skip(String[] ss, String skip) {421if (ss[0].startsWith(skip)) {422ss[0] = ss[0].substring(skip.length());423return true;424} else425return false;426}427}428429430