// Copyright 2012 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.collide.client.code.debugging; import com.google.collide.client.code.debugging.DebuggerApiTypes.RemoteObject; import com.google.collide.client.code.debugging.DebuggerApiTypes.RemoteObjectId; import com.google.collide.client.code.debugging.DebuggerApiTypes.RemoteObjectSubType; import com.google.collide.client.code.debugging.DebuggerApiTypes.RemoteObjectType; import com.google.collide.json.client.Jso; import com.google.collide.shared.util.StringUtils; import com.google.common.base.Objects; import javax.annotation.Nullable; /** * Utility helper class that contains browser independent methods on the * Debugger API. * */ class DebuggerApiUtils { /** * Casts a {@link RemoteObject} to a boolean value. * * @param remoteObject the remote object to cast * @return boolean value */ public static boolean castToBoolean(@Nullable RemoteObject remoteObject) { if (remoteObject == null || remoteObject.getType() == null) { return false; } switch (remoteObject.getType()) { case BOOLEAN: return "true".equals(remoteObject.getDescription()); case FUNCTION: return true; case NUMBER: if (isNonFiniteNumber(remoteObject)) { return !"NaN".equals(remoteObject.getDescription()); } else { return !StringUtils.isNullOrEmpty(remoteObject.getDescription()) && Double.parseDouble(remoteObject.getDescription()) != 0; } case OBJECT: return remoteObject.getSubType() != RemoteObjectSubType.NULL; case STRING: return !StringUtils.isNullOrEmpty(remoteObject.getDescription()); case UNDEFINED: return false; default: return false; } } /** * Adds a new field to a {@link Jso} object from a primitive * {@link RemoteObject}. * * <p>NOTE: Non finite numbers will not be added! * * @param jso object to add the new value to * @param key key name * @param remoteObject primitive remote object to extract the value from * @return true if the field was added successfully, false otherwise (for * example, if the {@code remoteObject} did not represent a primitive * value) */ public static boolean addPrimitiveJsoField(Jso jso, String key, RemoteObject remoteObject) { if (remoteObject == null || remoteObject.getType() == null) { return false; } switch (remoteObject.getType()) { case BOOLEAN: jso.addField(key, "true".equals(remoteObject.getDescription())); return true; case FUNCTION: return false; case NUMBER: if (!isNonFiniteNumber(remoteObject)) { jso.addField(key, Double.parseDouble(remoteObject.getDescription())); return true; } return false; case OBJECT: if (remoteObject.getSubType() == RemoteObjectSubType.NULL) { jso.addNullField(key); return true; } return false; case STRING: jso.addField(key, remoteObject.getDescription()); return true; case UNDEFINED: jso.addUndefinedField(key); return true; default: return false; } } /** * Checks whether the given {@link RemoteObject}s are equal. * * @param a first remote object * @param b second remote object * @return true if both of the arguments point to the same remote object in * the Debugger VM, or if they are both {@code null}s */ public static boolean equal(@Nullable RemoteObject a, @Nullable RemoteObject b) { if (a == b) { return true; } if (a == null || b == null) { return false; } return Objects.equal(a.getDescription(), b.getDescription()) && Objects.equal(a.hasChildren(), b.hasChildren()) && Objects.equal(a.getObjectId(), b.getObjectId()) && Objects.equal(a.getType(), b.getType()) && Objects.equal(a.getSubType(), b.getSubType()); } /** * Checks whether a given {@link RemoteObject} represents a non finite number * ({@code NaN}, {@code Infinity} or {@code -Infinity}). * * @param remoteObject the object to check * @return true if the remote object represents a non finite number */ public static boolean isNonFiniteNumber(RemoteObject remoteObject) { if (remoteObject.getType() != RemoteObjectType.NUMBER) { return false; } String description = remoteObject.getDescription(); return "NaN".equals(description) || "Infinity".equals(description) || "-Infinity".equals(description); } public static RemoteObject createRemoteObject(final String value) { return new RemoteObject() { @Override public String getDescription() { return value; } @Override public boolean hasChildren() { return false; } @Override public RemoteObjectId getObjectId() { return null; } @Override public RemoteObjectType getType() { return RemoteObjectType.STRING; } @Override public RemoteObjectSubType getSubType() { return null; } }; } }