| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library descriptor.file; | |
| 6 | |
| 7 import 'dart:async'; | |
| 8 import 'dart:convert'; | |
| 9 import 'dart:io'; | |
| 10 import 'dart:math' as math; | |
| 11 | |
| 12 import 'package:path/path.dart' as path; | |
| 13 import 'package:stack_trace/stack_trace.dart'; | |
| 14 | |
| 15 import '../../descriptor.dart'; | |
| 16 import '../../scheduled_test.dart'; | |
| 17 import '../utils.dart'; | |
| 18 | |
| 19 /// A descriptor describing a single file. | |
| 20 abstract class FileDescriptor extends Descriptor implements ReadableDescriptor { | |
| 21 /// The contents of the file, in bytes. | |
| 22 final List<int> contents; | |
| 23 | |
| 24 /// The contents of the file as a String. Assumes UTF-8 encoding. | |
| 25 String get textContents => new String.fromCharCodes(contents); | |
| 26 | |
| 27 /// Creates a new text [FileDescriptor] with [name] that matches its String | |
| 28 /// contents against [matcher]. If the file is created, it's considered to be | |
| 29 /// empty. | |
| 30 factory FileDescriptor.matcher(String name, Matcher matcher) => | |
| 31 new _MatcherFileDescriptor(name, matcher, isBinary: false); | |
| 32 | |
| 33 /// Creates a new binary [FileDescriptor] with [name] that matches its binary | |
| 34 /// contents against [matcher]. If the file is created, it's considered to be | |
| 35 /// empty. | |
| 36 factory FileDescriptor.binaryMatcher(String name, Matcher matcher) => | |
| 37 new _MatcherFileDescriptor(name, matcher, isBinary: true); | |
| 38 | |
| 39 /// Creates a new binary [FileDescriptor] descriptor with [name] and | |
| 40 /// [contents]. | |
| 41 factory FileDescriptor.binary(String name, List<int> contents) => | |
| 42 new _BinaryFileDescriptor(name, contents); | |
| 43 | |
| 44 /// Creates a new text [FileDescriptor] with [name] and [contents]. | |
| 45 factory FileDescriptor(String name, String contents) => | |
| 46 new _StringFileDescriptor(name, contents); | |
| 47 | |
| 48 FileDescriptor._(String name, this.contents) | |
| 49 : super(name); | |
| 50 | |
| 51 Future create([String parent]) => schedule(() { | |
| 52 if (parent == null) parent = defaultRoot; | |
| 53 return Chain.track(new File(path.join(parent, name)) | |
| 54 .writeAsBytes(contents)); | |
| 55 }, "creating file '$name'"); | |
| 56 | |
| 57 Future validate([String parent]) => | |
| 58 schedule(() => validateNow(parent), "validating file '$name'"); | |
| 59 | |
| 60 Future validateNow([String parent]) { | |
| 61 if (parent == null) parent = defaultRoot; | |
| 62 var fullPath = path.join(parent, name); | |
| 63 if (!new File(fullPath).existsSync()) { | |
| 64 fail("File not found: '$fullPath'."); | |
| 65 } | |
| 66 | |
| 67 return Chain.track(new File(fullPath).readAsBytes()).then(_validateNow); | |
| 68 } | |
| 69 | |
| 70 // TODO(nweiz): rather than setting up an inheritance chain, just store a | |
| 71 // Matcher for validation. This would require better error messages from the | |
| 72 // matcher library, though. | |
| 73 /// A function that throws an error if [binaryContents] doesn't match the | |
| 74 /// expected contents of the descriptor. | |
| 75 void _validateNow(List<int> binaryContents); | |
| 76 | |
| 77 Stream<List<int>> read() => new Future.value(contents).asStream(); | |
| 78 | |
| 79 String describe() => name; | |
| 80 } | |
| 81 | |
| 82 class _BinaryFileDescriptor extends FileDescriptor { | |
| 83 _BinaryFileDescriptor(String name, List<int> contents) | |
| 84 : super._(name, contents); | |
| 85 | |
| 86 Future _validateNow(List<int> actualContents) { | |
| 87 if (orderedIterableEquals(contents, actualContents)) return null; | |
| 88 // TODO(nweiz): show a hex dump here if the data is small enough. | |
| 89 fail("File '$name' didn't contain the expected binary data."); | |
| 90 } | |
| 91 } | |
| 92 | |
| 93 class _StringFileDescriptor extends FileDescriptor { | |
| 94 _StringFileDescriptor(String name, String contents) | |
| 95 : super._(name, UTF8.encode(contents)); | |
| 96 | |
| 97 Future _validateNow(List<int> actualContents) { | |
| 98 if (orderedIterableEquals(contents, actualContents)) return null; | |
| 99 throw _textMismatchMessage(textContents, | |
| 100 new String.fromCharCodes(actualContents)); | |
| 101 } | |
| 102 | |
| 103 String _textMismatchMessage(String expected, String actual) { | |
| 104 final expectedLines = expected.split('\n'); | |
| 105 final actualLines = actual.split('\n'); | |
| 106 | |
| 107 var results = []; | |
| 108 | |
| 109 // Compare them line by line to see which ones match. | |
| 110 var length = math.max(expectedLines.length, actualLines.length); | |
| 111 for (var i = 0; i < length; i++) { | |
| 112 if (i >= actualLines.length) { | |
| 113 // Missing output. | |
| 114 results.add('? ${expectedLines[i]}'); | |
| 115 } else if (i >= expectedLines.length) { | |
| 116 // Unexpected extra output. | |
| 117 results.add('X ${actualLines[i]}'); | |
| 118 } else { | |
| 119 var expectedLine = expectedLines[i]; | |
| 120 var actualLine = actualLines[i]; | |
| 121 | |
| 122 if (expectedLine != actualLine) { | |
| 123 // Mismatched lines. | |
| 124 results.add('X $actualLine'); | |
| 125 } else { | |
| 126 // Matched lines. | |
| 127 results.add('| $actualLine'); | |
| 128 } | |
| 129 } | |
| 130 } | |
| 131 | |
| 132 return "File '$name' should contain:\n" | |
| 133 "${prefixLines(expected)}\n" | |
| 134 "but actually contained:\n" | |
| 135 "${results.join('\n')}"; | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 class _MatcherFileDescriptor extends FileDescriptor { | |
| 140 final Matcher _matcher; | |
| 141 final bool _isBinary; | |
| 142 | |
| 143 _MatcherFileDescriptor(String name, this._matcher, {bool isBinary}) | |
| 144 : _isBinary = isBinary == true ? true : false, | |
| 145 super._(name, <int>[]); | |
| 146 | |
| 147 void _validateNow(List<int> actualContents) => | |
| 148 expect( | |
| 149 _isBinary ? actualContents : new String.fromCharCodes(actualContents), | |
| 150 _matcher); | |
| 151 } | |
| OLD | NEW |