// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. library utils; import 'dart:io'; import 'dart:math' show min; import 'dart:convert'; part 'legacy_path.dart'; class DebugLogger { static IOSink _sink; /** * If [path] was null, the DebugLogger will write messages to stdout. */ static init(Path path, {append: false}) { if (path != null) { var mode = append ? FileMode.APPEND : FileMode.WRITE; _sink = new File(path.toNativePath()).openWrite(mode: mode); } } static void close() { if (_sink != null) { _sink.close(); _sink = null; } } static String _formatErrorMessage(String msg, error) { if (error == null) return msg; msg += ": $error"; // TODO(floitsch): once the dart-executable that is bundled // with the Dart sources is updated, pass a trace parameter too and do: // if (trace != null) msg += "\nStackTrace: $trace"; return msg; } static void info(String msg, [error]) { msg = _formatErrorMessage(msg, error); _print("$_datetime Info: $msg"); } static void warning(String msg, [error]) { msg = _formatErrorMessage(msg, error); _print("$_datetime Warning: $msg"); } static void error(String msg, [error]) { msg = _formatErrorMessage(msg, error); _print("$_datetime Error: $msg"); } static void _print(String msg) { if (_sink != null) { _sink.writeln(msg); } else { print(msg); } } static String get _datetime => "${new DateTime.now()}"; } String prettifyJson(Object json, {int startIndentation: 0, int shiftWidth: 6}) { int currentIndentation = startIndentation; var buffer = new StringBuffer(); String indentationString() { return new List.filled(currentIndentation, ' ').join(''); } addString(String s, {bool indentation: true, bool newLine: true}) { if (indentation) { buffer.write(indentationString()); } buffer.write(s.replaceAll("\n", "\n${indentationString()}")); if (newLine) buffer.write("\n"); } prettifyJsonInternal( Object obj, {bool indentation: true, bool newLine: true}) { if (obj is List) { addString("[", indentation: indentation); currentIndentation += shiftWidth; for (var item in obj) { prettifyJsonInternal(item, indentation: indentation, newLine: false); addString(",", indentation: false); } currentIndentation -= shiftWidth; addString("]", indentation: indentation); } else if (obj is Map) { addString("{", indentation: indentation); currentIndentation += shiftWidth; for (var key in obj.keys) { addString("$key: ", indentation: indentation, newLine: false); currentIndentation += shiftWidth; prettifyJsonInternal(obj[key], indentation: false); currentIndentation -= shiftWidth; } currentIndentation -= shiftWidth; addString("}", indentation: indentation, newLine: newLine); } else { addString("$obj", indentation: indentation, newLine: newLine); } } prettifyJsonInternal(json); return buffer.toString(); } /** * [areByteArraysEqual] compares a range of bytes from [buffer1] with a * range of bytes from [buffer2]. * * Returns [true] if the [count] bytes in [buffer1] (starting at * [offset1]) match the [count] bytes in [buffer2] (starting at * [offset2]). * Otherwise [false] is returned. */ bool areByteArraysEqual(List buffer1, int offset1, List buffer2, int offset2, int count) { if ((offset1 + count) > buffer1.length || (offset2 + count) > buffer2.length) { return false; } for (var i = 0; i < count; i++) { if (buffer1[offset1 + i] != buffer2[offset2 + i]) { return false; } } return true; } /** * [findBytes] searches for [pattern] in [data] beginning at [startPos]. * * Returns [true] if [pattern] was found in [data]. * Otherwise [false] is returned. */ int findBytes(List data, List pattern, [int startPos=0]) { // TODO(kustermann): Use one of the fast string-matching algorithms! for (int i = startPos; i < (data.length - pattern.length); i++) { bool found = true; for (int j = 0; j < pattern.length; j++) { if (data[i + j] != pattern[j]) { found = false; break; } } if (found) { return i; } } return -1; } List encodeUtf8(String string) { return UTF8.encode(string); } // TODO(kustermann,ricow): As soon we have a debug log we should log // invalid utf8-encoded input to the log. // Currently invalid bytes will be replaced by a replacement character. String decodeUtf8(List bytes) { return UTF8.decode(bytes, allowMalformed: true); } class Locations { static String getBrowserLocation(String browserName, Map globalConfiguration) { var location = globalConfiguration[browserName]; if (location != null && location != '') { return location; } var browserLocations = { 'firefox': const { 'windows': 'C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe', 'linux': 'firefox', 'macos': '/Applications/Firefox.app/Contents/MacOS/firefox' }, 'chrome': const { 'windows': 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe', 'macos': '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', 'linux': 'google-chrome' }, 'dartium': const { 'windows': 'client\\tests\\dartium\\chrome.exe', 'macos': 'client/tests/dartium/Chromium.app/Contents/MacOS/Chromium', 'linux': 'client/tests/dartium/chrome' }, 'safari': const { 'macos': '/Applications/Safari.app/Contents/MacOS/Safari' }, 'ie9': const { 'windows': 'C:\\Program Files\\Internet Explorer\\iexplore.exe' }, 'ie10': const { 'windows': 'C:\\Program Files\\Internet Explorer\\iexplore.exe' }}; browserLocations['ff'] = browserLocations['firefox']; assert(browserLocations[browserName] != null); location = browserLocations[browserName][Platform.operatingSystem]; if (location != null) { return location; } else { throw '$browserName not supported on ${Platform.operatingSystem}'; } } } // This function is pretty stupid and only puts quotes around an argument if // it the argument contains a space. String escapeCommandLineArgument(String argument) { if (argument.contains(' ')) { return '"$argument"'; } return argument; } class HashCodeBuilder { int _value = 0; void add(Object object) { _value = ((_value * 31) ^ object.hashCode) & 0x3FFFFFFF; } int get value => _value; } bool deepJsonCompare(Object a, Object b) { if (a == null || a is num || a is String) { return a == b; } else if (a is List) { if (b is List) { if (a.length != b.length) return false; for (int i = 0; i < a.length; i++) { if (!deepJsonCompare(a[i], b[i])) return false; } return true; } return false; } else if (a is Map) { if (b is Map) { if (a.length != b.length) return false; for (var key in a.keys) { if (!b.containsKey(key)) return false; if (!deepJsonCompare(a[key], b[key])) return false; } return true; } return false; } else { throw new Exception("Can't compare two non json-like objects " "(a: ${a.runtimeType}, b: ${b.runtimeType})"); } } class UniqueObject { static int _nextId = 1; final int _hashCode; int get hashCode => _hashCode; operator==(other) => other is UniqueObject && _hashCode == other._hashCode; UniqueObject() : _hashCode = ++_nextId; }