OLD | NEW |
---|---|
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * A library for writing dart unit tests. | 6 * A library for writing dart unit tests. |
7 * | 7 * |
8 * ## Installing ## | 8 * ## Installing ## |
9 * | 9 * |
10 * Use [pub][] to install this package. Add the following to your `pubspec.yaml` | 10 * Use [pub][] to install this package. Add the following to your `pubspec.yaml` |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
160 * }); | 160 * }); |
161 * }); | 161 * }); |
162 * } | 162 * } |
163 * | 163 * |
164 * [pub]: http://pub.dartlang.org | 164 * [pub]: http://pub.dartlang.org |
165 * [pkg]: http://pub.dartlang.org/packages/unittest | 165 * [pkg]: http://pub.dartlang.org/packages/unittest |
166 */ | 166 */ |
167 library unittest; | 167 library unittest; |
168 | 168 |
169 import 'dart:async'; | 169 import 'dart:async'; |
170 import 'dart:collection'; | |
170 import 'dart:isolate'; | 171 import 'dart:isolate'; |
171 import 'dart:collection'; | 172 import 'dart:math'; |
Siggi Cherem (dart-lang)
2013/04/30 02:26:57
+ 'show max'
(it defines a lot of top-level names)
| |
172 import 'matcher.dart'; | 173 import 'matcher.dart'; |
173 export 'matcher.dart'; | 174 export 'matcher.dart'; |
174 | 175 |
175 // TODO(amouravski): We should not need to import mock here, but it's necessary | 176 // TODO(amouravski): We should not need to import mock here, but it's necessary |
176 // to enable dartdoc on the mock library, as it's not picked up normally. | 177 // to enable dartdoc on the mock library, as it's not picked up normally. |
177 import 'mock.dart'; | 178 import 'mock.dart'; |
178 | 179 |
179 part 'src/config.dart'; | 180 part 'src/config.dart'; |
180 part 'src/test_case.dart'; | 181 part 'src/test_case.dart'; |
181 | 182 |
182 Configuration _config; | 183 Configuration _config; |
183 | 184 |
184 /** [Configuration] used by the unittest library. */ | 185 /** |
185 Configuration get unittestConfiguration => _config; | 186 * [Configuration] used by the unittest library. Note that if a |
187 * configuration has not been set, calling this getter will create | |
188 * a default configuration. | |
189 */ | |
190 Configuration get unittestConfiguration { | |
191 if (_config == null) { | |
192 _config = new Configuration(); | |
193 } | |
194 return _config; | |
195 } | |
186 | 196 |
187 /** | 197 /** |
188 * Sets the [Configuration] used by the unittest library. | 198 * Sets the [Configuration] used by the unittest library. |
189 * | 199 * |
190 * Throws a [StateError] if there is an existing, incompatible value. | 200 * Throws a [StateError] if there is an existing, incompatible value. |
191 */ | 201 */ |
192 void set unittestConfiguration(Configuration value) { | 202 void set unittestConfiguration(Configuration value) { |
193 if(!identical(_config, value)) { | 203 if(!identical(_config, value)) { |
194 if(_config != null) { | 204 if(_config != null) { |
195 throw new StateError('unittestConfiguration has already been set'); | 205 throw new StateError('unittestConfiguration has already been set'); |
(...skipping 617 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
813 void _ensureInitialized(bool configAutoStart) { | 823 void _ensureInitialized(bool configAutoStart) { |
814 if (_initialized) { | 824 if (_initialized) { |
815 return; | 825 return; |
816 } | 826 } |
817 _initialized = true; | 827 _initialized = true; |
818 // Hook our async guard into the matcher library. | 828 // Hook our async guard into the matcher library. |
819 wrapAsync = (f, [id]) => expectAsync1(f, id: id); | 829 wrapAsync = (f, [id]) => expectAsync1(f, id: id); |
820 | 830 |
821 _uncaughtErrorMessage = null; | 831 _uncaughtErrorMessage = null; |
822 | 832 |
823 if (_config == null) { | 833 unittestConfiguration.onInit(); |
824 unittestConfiguration = new Configuration(); | |
825 } | |
826 _config.onInit(); | |
827 | 834 |
828 if (configAutoStart && _config.autoStart) { | 835 if (configAutoStart && _config.autoStart) { |
829 // Immediately queue the suite up. It will run after a timeout (i.e. after | 836 // Immediately queue the suite up. It will run after a timeout (i.e. after |
830 // main() has returned). | 837 // main() has returned). |
831 runAsync(runTests); | 838 runAsync(runTests); |
832 } | 839 } |
833 } | 840 } |
834 | 841 |
835 /** Select a solo test by ID. */ | 842 /** Select a solo test by ID. */ |
836 void setSoloTest(int id) => | 843 void setSoloTest(int id) => |
(...skipping 15 matching lines...) Expand all Loading... | |
852 } | 859 } |
853 | 860 |
854 /** Enable a test by ID. */ | 861 /** Enable a test by ID. */ |
855 void enableTest(int testId) => _setTestEnabledState(testId, true); | 862 void enableTest(int testId) => _setTestEnabledState(testId, true); |
856 | 863 |
857 /** Disable a test by ID. */ | 864 /** Disable a test by ID. */ |
858 void disableTest(int testId) => _setTestEnabledState(testId, false); | 865 void disableTest(int testId) => _setTestEnabledState(testId, false); |
859 | 866 |
860 /** Signature for a test function. */ | 867 /** Signature for a test function. */ |
861 typedef dynamic TestFunction(); | 868 typedef dynamic TestFunction(); |
869 | |
870 // Stack formatting utility. Strips extraneous content from a stack trace. | |
871 // Stack frame lines are parsed with a regexp, which has been tested | |
872 // in Chrome, Firefox and the VM. If a line fails to be parsed it is | |
873 // included in the output to be conservative. | |
874 // | |
875 // The output stack consists of everything after the call to TestCase._run. | |
876 // If we see an 'expect' in the frame we will prune everything above that | |
877 // as well. | |
878 final _frameRegExp = new RegExp( | |
879 r'^\s*' // Skip leading spaces. | |
880 r'(?:' // Group of choices for the prefix. | |
881 r'(?:#\d+\s*)|' // Skip VM's #<frameNumber>. | |
882 r'(?:at )|' // Skip Firefox's 'at '. | |
883 r'(?:))' // Other environments have nothing here. | |
884 r'(.+)' // Extract the function/method. | |
885 r'\s*[@\(]' // Skip space and @ or (. | |
886 r'(' // This group of choices is for the source file. | |
887 r'(?:.+:\/\/.+\/[^:]*)|' // Handle file:// or http:// URLs. | |
888 r'(?:dart:[^:]*)|' // Handle dart:<lib>. | |
889 r'(?:package:[^:]*)' // Handle package:<path> | |
890 r'):([:\d]+)[\)]?$'); // Get the line number and optional column number. | |
891 | |
892 String _formatStack(stack) { | |
893 var lines; | |
894 if (stack is StackTrace) { | |
895 lines = stack.toString().split('\n'); | |
896 } else if (stack is String) { | |
897 lines = stack.split('\n'); | |
898 } else { | |
899 return stack.toString(); | |
900 } | |
901 | |
902 // Calculate the max width of first column so we can | |
903 // pad to align the second columns. | |
904 int padding = lines.fold(0, (n, line) { | |
905 var match = _frameRegExp.firstMatch(line); | |
906 if (match == null) return n; | |
907 return max(n, match[1].length + 1); | |
908 }); | |
909 | |
910 // We remove all entries that have a location in unittest. | |
911 // We strip out anything before _nextBatch too. | |
912 var sb = new StringBuffer(); | |
913 for (var i = 0; i < lines.length; i++) { | |
914 var line = lines[i]; | |
915 if (line == '') continue; | |
916 var match = _frameRegExp.firstMatch(line); | |
917 if (match == null) { | |
918 sb.write(line); | |
919 sb.write('\n'); | |
920 } else { | |
921 var member = match[1]; | |
922 var location = match[2]; | |
923 var position = match[3]; | |
924 if (member.indexOf('TestCase._runTest') >= 0) { | |
925 // Don't include anything after this. | |
926 break; | |
927 } else if (member.indexOf('expect') >= 0) { | |
928 // It looks like this was an expect() failure; | |
929 // drop all the frames up to here. | |
930 sb.clear(); | |
931 } else { | |
932 sb.write(member); | |
933 // Pad second column to a fixed position. | |
934 for (var j = 0; j <= padding - member.length; j++) { | |
935 sb.write(' '); | |
936 } | |
937 sb.write(location); | |
938 sb.write(' '); | |
939 sb.write(position); | |
940 sb.write('\n'); | |
941 } | |
942 } | |
943 } | |
944 return sb.toString(); | |
945 } | |
OLD | NEW |