{"action":"created","comment":{"url":"https://api.github.com/repos/jayudey-wf/test/pulls/comments/47954961","id":47954961,"diff_hunk":"@@ -0,0 +1,363 @@\n+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file\n+// for details. All rights reserved. Use of this source code is governed by a\n+// BSD-style license that can be found in the LICENSE file.\n+\n+library test.runner.reporter.xunit;\n+\n+import 'dart:async';\n+\n+import '../../backend/live_test.dart';\n+import '../../backend/state.dart';\n+import '../../backend/group.dart';\n+import '../../frontend/expect.dart';\n+import '../../utils.dart';\n+import '../engine.dart';\n+import '../load_suite.dart';\n+import '../reporter.dart';\n+\n+class XunitFailureResult {\n+  String name;\n+  String stack;\n+\n+  XunitFailureResult(this.name, this.stack);\n+}\n+\n+class XunitTestResult {\n+  int beginningTime;\n+  int endTime;\n+  Map error = {};\n+  String name;\n+  String path;\n+  bool skipped = false;\n+  String skipReason;\n+\n+  XunitTestResult(this.name, this.path, this.beginningTime);\n+}\n+\n+class XunitTestSuite {\n+  int errored = 0;\n+  int failed = 0;\n+  int skipped = 0;\n+  List testResults = [];\n+  int tests = 0;\n+\n+  add(XunitTestResult test) {\n+    testResults.add(test);\n+  }\n+}\n+\n+/// A reporter that returns xunit compatible output.\n+\n+class XunitReporter implements Reporter {\n+  /// The engine used to run the tests.\n+  final Engine _engine;\n+\n+  /// A stopwatch that tracks the duration of the full run.\n+  final _stopwatch = new Stopwatch();\n+\n+  /// Whether we've started [_stopwatch].\n+  ///\n+  /// We can't just use `_stopwatch.isRunning` because the stopwatch is stopped\n+  /// when the reporter is paused.\n+  var _stopwatchStarted = false;\n+\n+  /// Whether the reporter is paused.\n+  var _paused = false;\n+\n+  /// The set of all subscriptions to various streams.\n+  final _subscriptions = new Set<StreamSubscription>();\n+\n+  /// Record of all tests run.\n+  Map _testCases = {};\n+\n+  /// Number of failures that occur during the test run.\n+  int _failureCount = 0;\n+\n+  /// Number of errors that occur during the test run.\n+  int _errorCount = 0;\n+\n+  /// Map containing Xunit hierarchy.\n+  Map _groupStructure = {};\n+\n+  /// Watches the tests run by [engine] and records its results.\n+  static XunitReporter watch(Engine engine, {bool verboseTrace: false}) {\n+    return new XunitReporter._(engine, verboseTrace: verboseTrace);\n+  }\n+\n+  XunitReporter._(this._engine, {bool verboseTrace: false}) {\n+    _subscriptions.add(_engine.onTestStarted.listen(_onTestStarted));\n+\n+    /// Convert the future to a stream so that the subscription can be paused or\n+    /// canceled.\n+    _subscriptions.add(_engine.success.asStream().listen(_onDone));\n+  }\n+\n+  void pause() {\n+    if (_paused) return;\n+    _paused = true;\n+\n+    _stopwatch.stop();\n+\n+    for (var subscription in _subscriptions) {\n+      subscription.pause();\n+    }\n+  }\n+\n+  void resume() {\n+    if (!_paused) return;\n+    if (_stopwatchStarted) _stopwatch.start();\n+\n+    for (var subscription in _subscriptions) {\n+      subscription.resume();\n+    }\n+  }\n+\n+  void cancel() {\n+    for (var subscription in _subscriptions) {\n+      subscription.cancel();\n+    }\n+    _subscriptions.clear();\n+  }\n+\n+  /// A callback called when the engine begins running [liveTest].\n+  void _onTestStarted(LiveTest liveTest) {\n+    if (liveTest.suite is! LoadSuite) {\n+      if (!_stopwatch.isRunning) _stopwatch.start();\n+\n+      // The engine surfaces load tests when there are no other tests running,\n+      // but because the expanded reporter's output is always visible, we don't\n+      // emit information about them unless they fail.\n+      _subscriptions.add(liveTest.onStateChange\n+          .listen((state) => _onStateChange(liveTest, state)));\n+    } else if (_engine.active.length == 1 &&\n+        _engine.active.first == liveTest &&\n+        liveTest.test.name.startsWith(\"compiling \")) {}\n+\n+    _subscriptions.add(liveTest.onError\n+        .listen((error) => _onError(liveTest, error.error, error.stackTrace)));\n+\n+    _subscriptions.add(liveTest.onPrint.listen((line) {}));\n+  }\n+\n+  /// Return an ordered list of groups that [liveTest] belongs to\n+  List _orderedGroupList(List<Group> listOfGroups) {\n+    List separatedList = [];\n+    for (int i = listOfGroups.length - 1; i >= 1; i--) {\n+      if (i > 1) {\n+        separatedList.add(listOfGroups[i]\n+            .name\n+            .replaceAll(listOfGroups[i - 1].name, '')\n+            .trim());\n+      } else {\n+        separatedList.add((listOfGroups[1].name));\n+      }\n+    }\n+    return (separatedList.reversed).toList();\n+  }\n+\n+  /// A callback called when [liveTest]'s state becomes [state].\n+  void _onStateChange(LiveTest liveTest, State state) {\n+    if (state.status != Status.complete) {\n+      if (state.status == Status.running) {\n+        if (!_testCases.containsKey(liveTest.test)) {\n+          String testName = liveTest.individualName;\n+          testName = testName.replaceAll('&', '&amp;');\n+          testName = testName.replaceAll('<', '&lt;');\n+          testName = testName.replaceAll('>', '&gt;');\n+          testName = testName.replaceAll('\"', '&quot;');\n+          testName = testName.replaceAll(\"'\", '&apos;');\n+\n+          _testCases[liveTest] = new XunitTestResult(\n+              testName, liveTest.suite.path, _stopwatch.elapsedMilliseconds);\n+          List listOfGroups = _orderedGroupList(liveTest.groups);\n+          Map listGroup = _groupStructure;\n+\n+          listOfGroups.forEach((elem) {\n+            if (!listGroup.containsKey(elem)) {\n+              listGroup[elem] = {'testResults': new XunitTestSuite()};\n+            }\n+            listGroup = listGroup[elem];\n+          });\n+\n+          listGroup['testResults'] ??= new XunitTestSuite();\n+\n+          listGroup['testResults'].add(_testCases[liveTest]);\n+        }\n+      }\n+      return;\n+    }\n+\n+    _testCases[liveTest].endTime = _stopwatch.elapsedMilliseconds;\n+\n+    if (liveTest.test.metadata.skip) {\n+      _testCases[liveTest].skipped = true;\n+    }\n+\n+    if (liveTest.test.metadata.skipReason != null) {","path":"lib/src/runner/reporter/xunit.dart","position":196,"original_position":196,"commit_id":"63639a657917ae79c9faf084689ac6fe5731eba1","original_commit_id":"63639a657917ae79c9faf084689ac6fe5731eba1","user":{"login":"trentgrover-wf","id":3778206,"avatar_url":"https://avatars.githubusercontent.com/u/3778206?v=3","gravatar_id":"","url":"https://api.github.com/users/trentgrover-wf","html_url":"https://github.com/trentgrover-wf","followers_url":"https://api.github.com/users/trentgrover-wf/followers","following_url":"https://api.github.com/users/trentgrover-wf/following{/other_user}","gists_url":"https://api.github.com/users/trentgrover-wf/gists{/gist_id}","starred_url":"https://api.github.com/users/trentgrover-wf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/trentgrover-wf/subscriptions","organizations_url":"https://api.github.com/users/trentgrover-wf/orgs","repos_url":"https://api.github.com/users/trentgrover-wf/repos","events_url":"https://api.github.com/users/trentgrover-wf/events{/privacy}","received_events_url":"https://api.github.com/users/trentgrover-wf/received_events","type":"User","site_admin":false},"body":"if this only applies when skipped is true, this can go inside the above if statement","created_at":"2015-12-17T20:12:58Z","updated_at":"2015-12-17T20:12:58Z","html_url":"https://github.com/jayudey-wf/test/pull/1#discussion_r47954961","pull_request_url":"https://api.github.com/repos/jayudey-wf/test/pulls/1","_links":{"self":{"href":"https://api.github.com/repos/jayudey-wf/test/pulls/comments/47954961"},"html":{"href":"https://github.com/jayudey-wf/test/pull/1#discussion_r47954961"},"pull_request":{"href":"https://api.github.com/repos/jayudey-wf/test/pulls/1"}}},"pull_request":{"url":"https://api.github.com/repos/jayudey-wf/test/pulls/1","id":53847044,"html_url":"https://github.com/jayudey-wf/test/pull/1","diff_url":"https://github.com/jayudey-wf/test/pull/1.diff","patch_url":"https://github.com/jayudey-wf/test/pull/1.patch","issue_url":"https://api.github.com/repos/jayudey-wf/test/issues/1","number":1,"state":"open","locked":false,"title":"Initial implementation at creating xunit reporter","user":{"login":"jayudey-wf","id":4429043,"avatar_url":"https://avatars.githubusercontent.com/u/4429043?v=3","gravatar_id":"","url":"https://api.github.com/users/jayudey-wf","html_url":"https://github.com/jayudey-wf","followers_url":"https://api.github.com/users/jayudey-wf/followers","following_url":"https://api.github.com/users/jayudey-wf/following{/other_user}","gists_url":"https://api.github.com/users/jayudey-wf/gists{/gist_id}","starred_url":"https://api.github.com/users/jayudey-wf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jayudey-wf/subscriptions","organizations_url":"https://api.github.com/users/jayudey-wf/orgs","repos_url":"https://api.github.com/users/jayudey-wf/repos","events_url":"https://api.github.com/users/jayudey-wf/events{/privacy}","received_events_url":"https://api.github.com/users/jayudey-wf/received_events","type":"User","site_admin":false},"body":"## Issue\r\n- It would be nice to have the test package produce xunit compatible output\r\n\r\n## Changes\r\n**Source:**\r\n- Added xunit reporter\r\n\r\n**Tests:**\r\n- Added\r\n\r\n## Areas of Regression\r\n- n/a\r\n\r\n## Testing\r\n- ensure that xunit xml is produced\r\n\r\n## Code Review\r\n@trentgrover-wf\r\n@maxwellpeterson-wf\r\n@evanweible-wf\r\n@dustinlessard-wf\r\n@christopherdaly-wf\r\n@micahbeeman-wf","created_at":"2015-12-16T14:23:59Z","updated_at":"2015-12-17T20:12:58Z","closed_at":null,"merged_at":null,"merge_commit_sha":"afff4599ac1eda3f37f50bfd6faefaab8c8c029e","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/jayudey-wf/test/pulls/1/commits","review_comments_url":"https://api.github.com/repos/jayudey-wf/test/pulls/1/comments","review_comment_url":"https://api.github.com/repos/jayudey-wf/test/pulls/comments{/number}","comments_url":"https://api.github.com/repos/jayudey-wf/test/issues/1/comments","statuses_url":"https://api.github.com/repos/jayudey-wf/test/statuses/63639a657917ae79c9faf084689ac6fe5731eba1","head":{"label":"jayudey-wf:xunit-reporter","ref":"xunit-reporter","sha":"63639a657917ae79c9faf084689ac6fe5731eba1","user":{"login":"jayudey-wf","id":4429043,"avatar_url":"https://avatars.githubusercontent.com/u/4429043?v=3","gravatar_id":"","url":"https://api.github.com/users/jayudey-wf","html_url":"https://github.com/jayudey-wf","followers_url":"https://api.github.com/users/jayudey-wf/followers","following_url":"https://api.github.com/users/jayudey-wf/following{/other_user}","gists_url":"https://api.github.com/users/jayudey-wf/gists{/gist_id}","starred_url":"https://api.github.com/users/jayudey-wf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jayudey-wf/subscriptions","organizations_url":"https://api.github.com/users/jayudey-wf/orgs","repos_url":"https://api.github.com/users/jayudey-wf/repos","events_url":"https://api.github.com/users/jayudey-wf/events{/privacy}","received_events_url":"https://api.github.com/users/jayudey-wf/received_events","type":"User","site_admin":false},"repo":{"id":47579079,"name":"test","full_name":"jayudey-wf/test","owner":{"login":"jayudey-wf","id":4429043,"avatar_url":"https://avatars.githubusercontent.com/u/4429043?v=3","gravatar_id":"","url":"https://api.github.com/users/jayudey-wf","html_url":"https://github.com/jayudey-wf","followers_url":"https://api.github.com/users/jayudey-wf/followers","following_url":"https://api.github.com/users/jayudey-wf/following{/other_user}","gists_url":"https://api.github.com/users/jayudey-wf/gists{/gist_id}","starred_url":"https://api.github.com/users/jayudey-wf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jayudey-wf/subscriptions","organizations_url":"https://api.github.com/users/jayudey-wf/orgs","repos_url":"https://api.github.com/users/jayudey-wf/repos","events_url":"https://api.github.com/users/jayudey-wf/events{/privacy}","received_events_url":"https://api.github.com/users/jayudey-wf/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/jayudey-wf/test","description":"A library for writing unit tests in Dart.","fork":true,"url":"https://api.github.com/repos/jayudey-wf/test","forks_url":"https://api.github.com/repos/jayudey-wf/test/forks","keys_url":"https://api.github.com/repos/jayudey-wf/test/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jayudey-wf/test/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jayudey-wf/test/teams","hooks_url":"https://api.github.com/repos/jayudey-wf/test/hooks","issue_events_url":"https://api.github.com/repos/jayudey-wf/test/issues/events{/number}","events_url":"https://api.github.com/repos/jayudey-wf/test/events","assignees_url":"https://api.github.com/repos/jayudey-wf/test/assignees{/user}","branches_url":"https://api.github.com/repos/jayudey-wf/test/branches{/branch}","tags_url":"https://api.github.com/repos/jayudey-wf/test/tags","blobs_url":"https://api.github.com/repos/jayudey-wf/test/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jayudey-wf/test/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jayudey-wf/test/git/refs{/sha}","trees_url":"https://api.github.com/repos/jayudey-wf/test/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jayudey-wf/test/statuses/{sha}","languages_url":"https://api.github.com/repos/jayudey-wf/test/languages","stargazers_url":"https://api.github.com/repos/jayudey-wf/test/stargazers","contributors_url":"https://api.github.com/repos/jayudey-wf/test/contributors","subscribers_url":"https://api.github.com/repos/jayudey-wf/test/subscribers","subscription_url":"https://api.github.com/repos/jayudey-wf/test/subscription","commits_url":"https://api.github.com/repos/jayudey-wf/test/commits{/sha}","git_commits_url":"https://api.github.com/repos/jayudey-wf/test/git/commits{/sha}","comments_url":"https://api.github.com/repos/jayudey-wf/test/comments{/number}","issue_comment_url":"https://api.github.com/repos/jayudey-wf/test/issues/comments{/number}","contents_url":"https://api.github.com/repos/jayudey-wf/test/contents/{+path}","compare_url":"https://api.github.com/repos/jayudey-wf/test/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jayudey-wf/test/merges","archive_url":"https://api.github.com/repos/jayudey-wf/test/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jayudey-wf/test/downloads","issues_url":"https://api.github.com/repos/jayudey-wf/test/issues{/number}","pulls_url":"https://api.github.com/repos/jayudey-wf/test/pulls{/number}","milestones_url":"https://api.github.com/repos/jayudey-wf/test/milestones{/number}","notifications_url":"https://api.github.com/repos/jayudey-wf/test/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jayudey-wf/test/labels{/name}","releases_url":"https://api.github.com/repos/jayudey-wf/test/releases{/id}","created_at":"2015-12-07T21:03:48Z","updated_at":"2015-12-07T21:03:49Z","pushed_at":"2015-12-16T16:01:44Z","git_url":"git://github.com/jayudey-wf/test.git","ssh_url":"git@github.com:jayudey-wf/test.git","clone_url":"https://github.com/jayudey-wf/test.git","svn_url":"https://github.com/jayudey-wf/test","homepage":"https://pub.dartlang.org/packages/test","size":2070,"stargazers_count":0,"watchers_count":0,"language":"Dart","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"jayudey-wf:master","ref":"master","sha":"a99ce0f666b2b12da30ef3522c99259b3ace1307","user":{"login":"jayudey-wf","id":4429043,"avatar_url":"https://avatars.githubusercontent.com/u/4429043?v=3","gravatar_id":"","url":"https://api.github.com/users/jayudey-wf","html_url":"https://github.com/jayudey-wf","followers_url":"https://api.github.com/users/jayudey-wf/followers","following_url":"https://api.github.com/users/jayudey-wf/following{/other_user}","gists_url":"https://api.github.com/users/jayudey-wf/gists{/gist_id}","starred_url":"https://api.github.com/users/jayudey-wf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jayudey-wf/subscriptions","organizations_url":"https://api.github.com/users/jayudey-wf/orgs","repos_url":"https://api.github.com/users/jayudey-wf/repos","events_url":"https://api.github.com/users/jayudey-wf/events{/privacy}","received_events_url":"https://api.github.com/users/jayudey-wf/received_events","type":"User","site_admin":false},"repo":{"id":47579079,"name":"test","full_name":"jayudey-wf/test","owner":{"login":"jayudey-wf","id":4429043,"avatar_url":"https://avatars.githubusercontent.com/u/4429043?v=3","gravatar_id":"","url":"https://api.github.com/users/jayudey-wf","html_url":"https://github.com/jayudey-wf","followers_url":"https://api.github.com/users/jayudey-wf/followers","following_url":"https://api.github.com/users/jayudey-wf/following{/other_user}","gists_url":"https://api.github.com/users/jayudey-wf/gists{/gist_id}","starred_url":"https://api.github.com/users/jayudey-wf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jayudey-wf/subscriptions","organizations_url":"https://api.github.com/users/jayudey-wf/orgs","repos_url":"https://api.github.com/users/jayudey-wf/repos","events_url":"https://api.github.com/users/jayudey-wf/events{/privacy}","received_events_url":"https://api.github.com/users/jayudey-wf/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/jayudey-wf/test","description":"A library for writing unit tests in Dart.","fork":true,"url":"https://api.github.com/repos/jayudey-wf/test","forks_url":"https://api.github.com/repos/jayudey-wf/test/forks","keys_url":"https://api.github.com/repos/jayudey-wf/test/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jayudey-wf/test/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jayudey-wf/test/teams","hooks_url":"https://api.github.com/repos/jayudey-wf/test/hooks","issue_events_url":"https://api.github.com/repos/jayudey-wf/test/issues/events{/number}","events_url":"https://api.github.com/repos/jayudey-wf/test/events","assignees_url":"https://api.github.com/repos/jayudey-wf/test/assignees{/user}","branches_url":"https://api.github.com/repos/jayudey-wf/test/branches{/branch}","tags_url":"https://api.github.com/repos/jayudey-wf/test/tags","blobs_url":"https://api.github.com/repos/jayudey-wf/test/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jayudey-wf/test/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jayudey-wf/test/git/refs{/sha}","trees_url":"https://api.github.com/repos/jayudey-wf/test/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jayudey-wf/test/statuses/{sha}","languages_url":"https://api.github.com/repos/jayudey-wf/test/languages","stargazers_url":"https://api.github.com/repos/jayudey-wf/test/stargazers","contributors_url":"https://api.github.com/repos/jayudey-wf/test/contributors","subscribers_url":"https://api.github.com/repos/jayudey-wf/test/subscribers","subscription_url":"https://api.github.com/repos/jayudey-wf/test/subscription","commits_url":"https://api.github.com/repos/jayudey-wf/test/commits{/sha}","git_commits_url":"https://api.github.com/repos/jayudey-wf/test/git/commits{/sha}","comments_url":"https://api.github.com/repos/jayudey-wf/test/comments{/number}","issue_comment_url":"https://api.github.com/repos/jayudey-wf/test/issues/comments{/number}","contents_url":"https://api.github.com/repos/jayudey-wf/test/contents/{+path}","compare_url":"https://api.github.com/repos/jayudey-wf/test/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jayudey-wf/test/merges","archive_url":"https://api.github.com/repos/jayudey-wf/test/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jayudey-wf/test/downloads","issues_url":"https://api.github.com/repos/jayudey-wf/test/issues{/number}","pulls_url":"https://api.github.com/repos/jayudey-wf/test/pulls{/number}","milestones_url":"https://api.github.com/repos/jayudey-wf/test/milestones{/number}","notifications_url":"https://api.github.com/repos/jayudey-wf/test/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jayudey-wf/test/labels{/name}","releases_url":"https://api.github.com/repos/jayudey-wf/test/releases{/id}","created_at":"2015-12-07T21:03:48Z","updated_at":"2015-12-07T21:03:49Z","pushed_at":"2015-12-16T16:01:44Z","git_url":"git://github.com/jayudey-wf/test.git","ssh_url":"git@github.com:jayudey-wf/test.git","clone_url":"https://github.com/jayudey-wf/test.git","svn_url":"https://github.com/jayudey-wf/test","homepage":"https://pub.dartlang.org/packages/test","size":2070,"stargazers_count":0,"watchers_count":0,"language":"Dart","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/jayudey-wf/test/pulls/1"},"html":{"href":"https://github.com/jayudey-wf/test/pull/1"},"issue":{"href":"https://api.github.com/repos/jayudey-wf/test/issues/1"},"comments":{"href":"https://api.github.com/repos/jayudey-wf/test/issues/1/comments"},"review_comments":{"href":"https://api.github.com/repos/jayudey-wf/test/pulls/1/comments"},"review_comment":{"href":"https://api.github.com/repos/jayudey-wf/test/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/jayudey-wf/test/pulls/1/commits"},"statuses":{"href":"https://api.github.com/repos/jayudey-wf/test/statuses/63639a657917ae79c9faf084689ac6fe5731eba1"}}}}