Index: packages/logging/test/logging_test.dart |
diff --git a/packages/logging/test/logging_test.dart b/packages/logging/test/logging_test.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2f5bf60e45f74cf4436b77c25d6e1f77de9d7c60 |
--- /dev/null |
+++ b/packages/logging/test/logging_test.dart |
@@ -0,0 +1,608 @@ |
+// Copyright (c) 2012, 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 logging_test; |
+ |
+import 'dart:async'; |
+ |
+import 'package:logging/logging.dart'; |
+import 'package:test/test.dart'; |
+ |
+void main() { |
+ test('level comparison is a valid comparator', () { |
+ var level1 = const Level('NOT_REAL1', 253); |
+ expect(level1 == level1, isTrue); |
+ expect(level1 <= level1, isTrue); |
+ expect(level1 >= level1, isTrue); |
+ expect(level1 < level1, isFalse); |
+ expect(level1 > level1, isFalse); |
+ |
+ var level2 = const Level('NOT_REAL2', 455); |
+ expect(level1 <= level2, isTrue); |
+ expect(level1 < level2, isTrue); |
+ expect(level2 >= level1, isTrue); |
+ expect(level2 > level1, isTrue); |
+ |
+ var level3 = const Level('NOT_REAL3', 253); |
+ expect(level1, isNot(same(level3))); // different instances |
+ expect(level1, equals(level3)); // same value. |
+ }); |
+ |
+ test('default levels are in order', () { |
+ final levels = Level.LEVELS; |
+ |
+ for (int i = 0; i < levels.length; i++) { |
+ for (int j = i + 1; j < levels.length; j++) { |
+ expect(levels[i] < levels[j], isTrue); |
+ } |
+ } |
+ }); |
+ |
+ test('levels are comparable', () { |
+ final unsorted = [ |
+ Level.INFO, |
+ Level.CONFIG, |
+ Level.FINE, |
+ Level.SHOUT, |
+ Level.OFF, |
+ Level.FINER, |
+ Level.ALL, |
+ Level.WARNING, |
+ Level.FINEST, |
+ Level.SEVERE, |
+ ]; |
+ |
+ final sorted = Level.LEVELS; |
+ |
+ expect(unsorted, isNot(orderedEquals(sorted))); |
+ |
+ unsorted.sort(); |
+ expect(unsorted, orderedEquals(sorted)); |
+ }); |
+ |
+ test('levels are hashable', () { |
+ var map = new Map<Level, String>(); |
+ map[Level.INFO] = 'info'; |
+ map[Level.SHOUT] = 'shout'; |
+ expect(map[Level.INFO], same('info')); |
+ expect(map[Level.SHOUT], same('shout')); |
+ }); |
+ |
+ test('logger name cannot start with a "." ', () { |
+ expect(() => new Logger('.c'), throwsArgumentError); |
+ }); |
+ |
+ test('logger naming is hierarchical', () { |
+ Logger c = new Logger('a.b.c'); |
+ expect(c.name, equals('c')); |
+ expect(c.parent.name, equals('b')); |
+ expect(c.parent.parent.name, equals('a')); |
+ expect(c.parent.parent.parent.name, equals('')); |
+ expect(c.parent.parent.parent.parent, isNull); |
+ }); |
+ |
+ test('logger full name', () { |
+ Logger c = new Logger('a.b.c'); |
+ expect(c.fullName, equals('a.b.c')); |
+ expect(c.parent.fullName, equals('a.b')); |
+ expect(c.parent.parent.fullName, equals('a')); |
+ expect(c.parent.parent.parent.fullName, equals('')); |
+ expect(c.parent.parent.parent.parent, isNull); |
+ }); |
+ |
+ test('logger parent-child links are correct', () { |
+ Logger a = new Logger('a'); |
+ Logger b = new Logger('a.b'); |
+ Logger c = new Logger('a.c'); |
+ expect(a, same(b.parent)); |
+ expect(a, same(c.parent)); |
+ expect(a.children['b'], same(b)); |
+ expect(a.children['c'], same(c)); |
+ }); |
+ |
+ test('loggers are singletons', () { |
+ Logger a1 = new Logger('a'); |
+ Logger a2 = new Logger('a'); |
+ Logger b = new Logger('a.b'); |
+ Logger root = Logger.root; |
+ expect(a1, same(a2)); |
+ expect(a1, same(b.parent)); |
+ expect(root, same(a1.parent)); |
+ expect(root, same(new Logger(''))); |
+ }); |
+ |
+ test('cannot directly manipulate Logger.children', () { |
+ var loggerAB = new Logger('a.b'); |
+ var loggerA = loggerAB.parent; |
+ |
+ expect(loggerA.children['b'], same(loggerAB), reason: 'can read Children'); |
+ |
+ expect(() { |
+ loggerAB.children['test'] = null; |
+ }, throwsUnsupportedError, reason: 'Children is read-only'); |
+ }); |
+ |
+ test('stackTrace gets throw to LogRecord', () { |
+ Logger.root.level = Level.INFO; |
+ |
+ var records = new List<LogRecord>(); |
+ |
+ var sub = Logger.root.onRecord.listen(records.add); |
+ |
+ try { |
+ throw new UnsupportedError('test exception'); |
+ } catch (error, stack) { |
+ Logger.root.log(Level.SEVERE, 'severe', error, stack); |
+ Logger.root.warning('warning', error, stack); |
+ } |
+ |
+ Logger.root.log(Level.SHOUT, 'shout'); |
+ |
+ sub.cancel(); |
+ |
+ expect(records, hasLength(3)); |
+ |
+ var severe = records[0]; |
+ expect(severe.message, 'severe'); |
+ expect(severe.error is UnsupportedError, isTrue); |
+ expect(severe.stackTrace is StackTrace, isTrue); |
+ |
+ var warning = records[1]; |
+ expect(warning.message, 'warning'); |
+ expect(warning.error is UnsupportedError, isTrue); |
+ expect(warning.stackTrace is StackTrace, isTrue); |
+ |
+ var shout = records[2]; |
+ expect(shout.message, 'shout'); |
+ expect(shout.error, isNull); |
+ expect(shout.stackTrace, isNull); |
+ }); |
+ |
+ group('zone gets recorded to LogRecord', () { |
+ test('root zone', () { |
+ var root = Logger.root; |
+ |
+ var recordingZone = Zone.current; |
+ var records = new List<LogRecord>(); |
+ root.onRecord.listen(records.add); |
+ root.info('hello'); |
+ |
+ expect(records, hasLength(1)); |
+ expect(records.first.zone, equals(recordingZone)); |
+ }); |
+ |
+ test('child zone', () { |
+ var root = Logger.root; |
+ |
+ var recordingZone; |
+ var records = new List<LogRecord>(); |
+ root.onRecord.listen(records.add); |
+ |
+ runZoned(() { |
+ recordingZone = Zone.current; |
+ root.info('hello'); |
+ }); |
+ |
+ expect(records, hasLength(1)); |
+ expect(records.first.zone, equals(recordingZone)); |
+ }); |
+ |
+ test('custom zone', () { |
+ var root = Logger.root; |
+ |
+ var recordingZone; |
+ var records = new List<LogRecord>(); |
+ root.onRecord.listen(records.add); |
+ |
+ runZoned(() { |
+ recordingZone = Zone.current; |
+ }); |
+ |
+ runZoned(() => root.log(Level.INFO, 'hello', null, null, recordingZone)); |
+ |
+ expect(records, hasLength(1)); |
+ expect(records.first.zone, equals(recordingZone)); |
+ }); |
+ }); |
+ |
+ group('detached loggers', () { |
+ test("create new instances of Logger", () { |
+ Logger a1 = new Logger.detached("a"); |
+ Logger a2 = new Logger.detached("a"); |
+ Logger a = new Logger("a"); |
+ |
+ expect(a1, isNot(a2)); |
+ expect(a1, isNot(a)); |
+ expect(a2, isNot(a)); |
+ }); |
+ |
+ test("parent is null", () { |
+ Logger a = new Logger.detached("a"); |
+ expect(a.parent, null); |
+ }); |
+ |
+ test("children is empty", () { |
+ Logger a = new Logger.detached("a"); |
+ expect(a.children, {}); |
+ }); |
+ }); |
+ |
+ group('mutating levels', () { |
+ Logger root = Logger.root; |
+ Logger a = new Logger('a'); |
+ Logger b = new Logger('a.b'); |
+ Logger c = new Logger('a.b.c'); |
+ Logger d = new Logger('a.b.c.d'); |
+ Logger e = new Logger('a.b.c.d.e'); |
+ |
+ setUp(() { |
+ hierarchicalLoggingEnabled = true; |
+ root.level = Level.INFO; |
+ a.level = null; |
+ b.level = null; |
+ c.level = null; |
+ d.level = null; |
+ e.level = null; |
+ root.clearListeners(); |
+ a.clearListeners(); |
+ b.clearListeners(); |
+ c.clearListeners(); |
+ d.clearListeners(); |
+ e.clearListeners(); |
+ hierarchicalLoggingEnabled = false; |
+ root.level = Level.INFO; |
+ }); |
+ |
+ test('cannot set level if hierarchy is disabled', () { |
+ expect(() { |
+ a.level = Level.FINE; |
+ }, throwsUnsupportedError); |
+ }); |
+ |
+ test('loggers effective level - no hierarchy', () { |
+ expect(root.level, equals(Level.INFO)); |
+ expect(a.level, equals(Level.INFO)); |
+ expect(b.level, equals(Level.INFO)); |
+ |
+ root.level = Level.SHOUT; |
+ |
+ expect(root.level, equals(Level.SHOUT)); |
+ expect(a.level, equals(Level.SHOUT)); |
+ expect(b.level, equals(Level.SHOUT)); |
+ }); |
+ |
+ test('loggers effective level - with hierarchy', () { |
+ hierarchicalLoggingEnabled = true; |
+ expect(root.level, equals(Level.INFO)); |
+ expect(a.level, equals(Level.INFO)); |
+ expect(b.level, equals(Level.INFO)); |
+ expect(c.level, equals(Level.INFO)); |
+ |
+ root.level = Level.SHOUT; |
+ b.level = Level.FINE; |
+ |
+ expect(root.level, equals(Level.SHOUT)); |
+ expect(a.level, equals(Level.SHOUT)); |
+ expect(b.level, equals(Level.FINE)); |
+ expect(c.level, equals(Level.FINE)); |
+ }); |
+ |
+ test('isLoggable is appropriate', () { |
+ hierarchicalLoggingEnabled = true; |
+ root.level = Level.SEVERE; |
+ c.level = Level.ALL; |
+ e.level = Level.OFF; |
+ |
+ expect(root.isLoggable(Level.SHOUT), isTrue); |
+ expect(root.isLoggable(Level.SEVERE), isTrue); |
+ expect(root.isLoggable(Level.WARNING), isFalse); |
+ expect(c.isLoggable(Level.FINEST), isTrue); |
+ expect(c.isLoggable(Level.FINE), isTrue); |
+ expect(e.isLoggable(Level.SHOUT), isFalse); |
+ }); |
+ |
+ test('add/remove handlers - no hierarchy', () { |
+ int calls = 0; |
+ var handler = (_) { |
+ calls++; |
+ }; |
+ final sub = c.onRecord.listen(handler); |
+ root.info("foo"); |
+ root.info("foo"); |
+ expect(calls, equals(2)); |
+ sub.cancel(); |
+ root.info("foo"); |
+ expect(calls, equals(2)); |
+ }); |
+ |
+ test('add/remove handlers - with hierarchy', () { |
+ hierarchicalLoggingEnabled = true; |
+ int calls = 0; |
+ var handler = (_) { |
+ calls++; |
+ }; |
+ c.onRecord.listen(handler); |
+ root.info("foo"); |
+ root.info("foo"); |
+ expect(calls, equals(0)); |
+ }); |
+ |
+ test('logging methods store appropriate level', () { |
+ root.level = Level.ALL; |
+ var rootMessages = []; |
+ root.onRecord.listen((record) { |
+ rootMessages.add('${record.level}: ${record.message}'); |
+ }); |
+ |
+ root.finest('1'); |
+ root.finer('2'); |
+ root.fine('3'); |
+ root.config('4'); |
+ root.info('5'); |
+ root.warning('6'); |
+ root.severe('7'); |
+ root.shout('8'); |
+ |
+ expect(rootMessages, equals([ |
+ 'FINEST: 1', |
+ 'FINER: 2', |
+ 'FINE: 3', |
+ 'CONFIG: 4', |
+ 'INFO: 5', |
+ 'WARNING: 6', |
+ 'SEVERE: 7', |
+ 'SHOUT: 8' |
+ ])); |
+ }); |
+ |
+ test('logging methods store exception', () { |
+ root.level = Level.ALL; |
+ var rootMessages = []; |
+ root.onRecord.listen((r) { |
+ rootMessages.add('${r.level}: ${r.message} ${r.error}'); |
+ }); |
+ |
+ root.finest('1'); |
+ root.finer('2'); |
+ root.fine('3'); |
+ root.config('4'); |
+ root.info('5'); |
+ root.warning('6'); |
+ root.severe('7'); |
+ root.shout('8'); |
+ root.finest('1', 'a'); |
+ root.finer('2', 'b'); |
+ root.fine('3', ['c']); |
+ root.config('4', 'd'); |
+ root.info('5', 'e'); |
+ root.warning('6', 'f'); |
+ root.severe('7', 'g'); |
+ root.shout('8', 'h'); |
+ |
+ expect(rootMessages, equals([ |
+ 'FINEST: 1 null', |
+ 'FINER: 2 null', |
+ 'FINE: 3 null', |
+ 'CONFIG: 4 null', |
+ 'INFO: 5 null', |
+ 'WARNING: 6 null', |
+ 'SEVERE: 7 null', |
+ 'SHOUT: 8 null', |
+ 'FINEST: 1 a', |
+ 'FINER: 2 b', |
+ 'FINE: 3 [c]', |
+ 'CONFIG: 4 d', |
+ 'INFO: 5 e', |
+ 'WARNING: 6 f', |
+ 'SEVERE: 7 g', |
+ 'SHOUT: 8 h' |
+ ])); |
+ }); |
+ |
+ test('message logging - no hierarchy', () { |
+ root.level = Level.WARNING; |
+ var rootMessages = []; |
+ var aMessages = []; |
+ var cMessages = []; |
+ c.onRecord.listen((record) { |
+ cMessages.add('${record.level}: ${record.message}'); |
+ }); |
+ a.onRecord.listen((record) { |
+ aMessages.add('${record.level}: ${record.message}'); |
+ }); |
+ root.onRecord.listen((record) { |
+ rootMessages.add('${record.level}: ${record.message}'); |
+ }); |
+ |
+ root.info('1'); |
+ root.fine('2'); |
+ root.shout('3'); |
+ |
+ b.info('4'); |
+ b.severe('5'); |
+ b.warning('6'); |
+ b.fine('7'); |
+ |
+ c.fine('8'); |
+ c.warning('9'); |
+ c.shout('10'); |
+ |
+ expect(rootMessages, equals([ |
+ // 'INFO: 1' is not loggable |
+ // 'FINE: 2' is not loggable |
+ 'SHOUT: 3', |
+ // 'INFO: 4' is not loggable |
+ 'SEVERE: 5', |
+ 'WARNING: 6', |
+ // 'FINE: 7' is not loggable |
+ // 'FINE: 8' is not loggable |
+ 'WARNING: 9', |
+ 'SHOUT: 10' |
+ ])); |
+ |
+ // no hierarchy means we all hear the same thing. |
+ expect(aMessages, equals(rootMessages)); |
+ expect(cMessages, equals(rootMessages)); |
+ }); |
+ |
+ test('message logging - with hierarchy', () { |
+ hierarchicalLoggingEnabled = true; |
+ |
+ b.level = Level.WARNING; |
+ |
+ var rootMessages = []; |
+ var aMessages = []; |
+ var cMessages = []; |
+ c.onRecord.listen((record) { |
+ cMessages.add('${record.level}: ${record.message}'); |
+ }); |
+ a.onRecord.listen((record) { |
+ aMessages.add('${record.level}: ${record.message}'); |
+ }); |
+ root.onRecord.listen((record) { |
+ rootMessages.add('${record.level}: ${record.message}'); |
+ }); |
+ |
+ root.info('1'); |
+ root.fine('2'); |
+ root.shout('3'); |
+ |
+ b.info('4'); |
+ b.severe('5'); |
+ b.warning('6'); |
+ b.fine('7'); |
+ |
+ c.fine('8'); |
+ c.warning('9'); |
+ c.shout('10'); |
+ |
+ expect(rootMessages, equals([ |
+ 'INFO: 1', |
+ // 'FINE: 2' is not loggable |
+ 'SHOUT: 3', |
+ // 'INFO: 4' is not loggable |
+ 'SEVERE: 5', |
+ 'WARNING: 6', |
+ // 'FINE: 7' is not loggable |
+ // 'FINE: 8' is not loggable |
+ 'WARNING: 9', |
+ 'SHOUT: 10' |
+ ])); |
+ |
+ expect(aMessages, equals([ |
+ // 1,2 and 3 are lower in the hierarchy |
+ // 'INFO: 4' is not loggable |
+ 'SEVERE: 5', |
+ 'WARNING: 6', |
+ // 'FINE: 7' is not loggable |
+ // 'FINE: 8' is not loggable |
+ 'WARNING: 9', |
+ 'SHOUT: 10' |
+ ])); |
+ |
+ expect(cMessages, equals([ |
+ // 1 - 7 are lower in the hierarchy |
+ // 'FINE: 8' is not loggable |
+ 'WARNING: 9', |
+ 'SHOUT: 10' |
+ ])); |
+ }); |
+ |
+ test('message logging - lazy functions', () { |
+ root.level = Level.INFO; |
+ var messages = []; |
+ root.onRecord.listen((record) { |
+ messages.add('${record.level}: ${record.message}'); |
+ }); |
+ |
+ var callCount = 0; |
+ var myClosure = () => "${++callCount}"; |
+ |
+ root.info(myClosure); |
+ root.finer(myClosure); // Should not get evaluated. |
+ root.warning(myClosure); |
+ |
+ expect(messages, equals(['INFO: 1', 'WARNING: 2',])); |
+ }); |
+ |
+ test('message logging - calls toString', () { |
+ root.level = Level.INFO; |
+ var messages = []; |
+ root.onRecord.listen((record) { |
+ messages.add('${record.level}: ${record.message}'); |
+ }); |
+ |
+ root.info(5); |
+ root.info(false); |
+ root.info([1, 2, 3]); |
+ root.info(() => 10); |
+ |
+ expect(messages, |
+ equals(['INFO: 5', 'INFO: false', 'INFO: [1, 2, 3]', 'INFO: 10',])); |
+ }); |
+ }); |
+ |
+ group('recordStackTraceAtLevel', () { |
+ var root = Logger.root; |
+ tearDown(() { |
+ recordStackTraceAtLevel = Level.OFF; |
+ root.clearListeners(); |
+ }); |
+ |
+ test('no stack trace by default', () { |
+ var records = new List<LogRecord>(); |
+ root.onRecord.listen(records.add); |
+ root.severe('hello'); |
+ root.warning('hello'); |
+ root.info('hello'); |
+ expect(records, hasLength(3)); |
+ expect(records[0].stackTrace, isNull); |
+ expect(records[1].stackTrace, isNull); |
+ expect(records[2].stackTrace, isNull); |
+ }); |
+ |
+ test('trace recorded only on requested levels', () { |
+ var records = new List<LogRecord>(); |
+ recordStackTraceAtLevel = Level.WARNING; |
+ root.onRecord.listen(records.add); |
+ root.severe('hello'); |
+ root.warning('hello'); |
+ root.info('hello'); |
+ expect(records, hasLength(3)); |
+ expect(records[0].stackTrace, isNotNull); |
+ expect(records[1].stackTrace, isNotNull); |
+ expect(records[2].stackTrace, isNull); |
+ }); |
+ |
+ test('provided trace is used if given', () { |
+ var trace; |
+ try { |
+ throw 'trace'; |
+ } catch(e, t) { |
+ trace = t; |
+ } |
+ var records = new List<LogRecord>(); |
+ recordStackTraceAtLevel = Level.WARNING; |
+ root.onRecord.listen(records.add); |
+ root.severe('hello'); |
+ root.warning('hello', 'a', trace); |
+ expect(records, hasLength(2)); |
+ expect(records[0].stackTrace, isNot(equals(trace))); |
+ expect(records[1].stackTrace, trace); |
+ }); |
+ |
+ test('error also generated when generating a trace', () { |
+ var records = new List<LogRecord>(); |
+ recordStackTraceAtLevel = Level.WARNING; |
+ root.onRecord.listen(records.add); |
+ root.severe('hello'); |
+ root.warning('hello'); |
+ root.info('hello'); |
+ expect(records, hasLength(3)); |
+ expect(records[0].error, isNotNull); |
+ expect(records[1].error, isNotNull); |
+ expect(records[2].error, isNull); |
+ }); |
+ }); |
+} |