| Index: sdk/lib/_internal/pub/test/version_solver_test.dart
 | 
| diff --git a/sdk/lib/_internal/pub/test/version_solver_test.dart b/sdk/lib/_internal/pub/test/version_solver_test.dart
 | 
| index d387ab4a007439557bf84d9074c0ce48b2138c39..00b3e1bb41624dfaaf58dc521c5b68973b0e4039 100644
 | 
| --- a/sdk/lib/_internal/pub/test/version_solver_test.dart
 | 
| +++ b/sdk/lib/_internal/pub/test/version_solver_test.dart
 | 
| @@ -41,6 +41,7 @@ main() {
 | 
|    group('backtracking', backtracking);
 | 
|    group('SDK constraint', sdkConstraint);
 | 
|    group('pre-release', prerelease);
 | 
| +  group('override', override);
 | 
|  }
 | 
|  
 | 
|  void basicGraph() {
 | 
| @@ -855,27 +856,158 @@ void prerelease() {
 | 
|    });
 | 
|  }
 | 
|  
 | 
| -testResolve(description, packages, {
 | 
| -             lockfile, result, FailMatcherBuilder error, int maxTries,
 | 
| -             bool useBleedingEdgeSdkVersion}) {
 | 
| -  _testResolve(test, description, packages, lockfile: lockfile, result: result,
 | 
| -      error: error, maxTries: maxTries,
 | 
| +void override() {
 | 
| +  testResolve('chooses best version matching override constraint', {
 | 
| +    'myapp 0.0.0': {
 | 
| +      'a': 'any'
 | 
| +    },
 | 
| +    'a 1.0.0': {},
 | 
| +    'a 2.0.0': {},
 | 
| +    'a 3.0.0': {}
 | 
| +  }, overrides: {
 | 
| +    'a': '<3.0.0'
 | 
| +  }, result: {
 | 
| +    'myapp from root': '0.0.0',
 | 
| +    'a': '2.0.0'
 | 
| +  });
 | 
| +
 | 
| +  testResolve('uses override as dependency', {
 | 
| +    'myapp 0.0.0': {},
 | 
| +    'a 1.0.0': {},
 | 
| +    'a 2.0.0': {},
 | 
| +    'a 3.0.0': {}
 | 
| +  }, overrides: {
 | 
| +    'a': '<3.0.0'
 | 
| +  }, result: {
 | 
| +    'myapp from root': '0.0.0',
 | 
| +    'a': '2.0.0'
 | 
| +  });
 | 
| +
 | 
| +  testResolve('ignores other constraints on overridden package', {
 | 
| +    'myapp 0.0.0': {
 | 
| +      'b': 'any',
 | 
| +      'c': 'any'
 | 
| +    },
 | 
| +    'a 1.0.0': {},
 | 
| +    'a 2.0.0': {},
 | 
| +    'a 3.0.0': {},
 | 
| +    'b 1.0.0': {
 | 
| +      'a': '1.0.0'
 | 
| +    },
 | 
| +    'c 1.0.0': {
 | 
| +      'a': '3.0.0'
 | 
| +    }
 | 
| +  }, overrides: {
 | 
| +    'a': '2.0.0'
 | 
| +  }, result: {
 | 
| +    'myapp from root': '0.0.0',
 | 
| +    'a': '2.0.0',
 | 
| +    'b': '1.0.0',
 | 
| +    'c': '1.0.0'
 | 
| +  });
 | 
| +
 | 
| +  testResolve('backtracks on overidden package for its constraints', {
 | 
| +    'myapp 0.0.0': {
 | 
| +      'shared': '2.0.0'
 | 
| +    },
 | 
| +    'a 1.0.0': {
 | 
| +      'shared': 'any'
 | 
| +    },
 | 
| +    'a 2.0.0': {
 | 
| +      'shared': '1.0.0'
 | 
| +    },
 | 
| +    'shared 1.0.0': {},
 | 
| +    'shared 2.0.0': {}
 | 
| +  }, overrides: {
 | 
| +    'a': '<3.0.0'
 | 
| +  }, result: {
 | 
| +    'myapp from root': '0.0.0',
 | 
| +    'a': '1.0.0',
 | 
| +    'shared': '2.0.0'
 | 
| +  }, maxTries: 2);
 | 
| +
 | 
| +  testResolve('override compatible with locked dependency', {
 | 
| +    'myapp 0.0.0': {
 | 
| +      'foo': 'any'
 | 
| +    },
 | 
| +    'foo 1.0.0': { 'bar': '1.0.0' },
 | 
| +    'foo 1.0.1': { 'bar': '1.0.1' },
 | 
| +    'foo 1.0.2': { 'bar': '1.0.2' },
 | 
| +    'bar 1.0.0': {},
 | 
| +    'bar 1.0.1': {},
 | 
| +    'bar 1.0.2': {}
 | 
| +  }, lockfile: {
 | 
| +    'foo': '1.0.1'
 | 
| +  }, overrides: {
 | 
| +    'foo': '<1.0.2'
 | 
| +  }, result: {
 | 
| +    'myapp from root': '0.0.0',
 | 
| +    'foo': '1.0.1',
 | 
| +    'bar': '1.0.1'
 | 
| +  });
 | 
| +
 | 
| +  testResolve('override incompatible with locked dependency', {
 | 
| +    'myapp 0.0.0': {
 | 
| +      'foo': 'any'
 | 
| +    },
 | 
| +    'foo 1.0.0': { 'bar': '1.0.0' },
 | 
| +    'foo 1.0.1': { 'bar': '1.0.1' },
 | 
| +    'foo 1.0.2': { 'bar': '1.0.2' },
 | 
| +    'bar 1.0.0': {},
 | 
| +    'bar 1.0.1': {},
 | 
| +    'bar 1.0.2': {}
 | 
| +  }, lockfile: {
 | 
| +    'foo': '1.0.1'
 | 
| +  }, overrides: {
 | 
| +    'foo': '>1.0.1'
 | 
| +  }, result: {
 | 
| +    'myapp from root': '0.0.0',
 | 
| +    'foo': '1.0.2',
 | 
| +    'bar': '1.0.2'
 | 
| +  });
 | 
| +
 | 
| +  testResolve('no version that matches override', {
 | 
| +    'myapp 0.0.0': {},
 | 
| +    'foo 2.0.0': {},
 | 
| +    'foo 2.1.3': {}
 | 
| +  }, overrides: {
 | 
| +    'foo': '>=1.0.0 <2.0.0'
 | 
| +  }, error: noVersion(['myapp']));
 | 
| +
 | 
| +  testResolve('override a bad source without error', {
 | 
| +    'myapp 0.0.0': {
 | 
| +      'foo from bad': 'any'
 | 
| +    },
 | 
| +    'foo 0.0.0': {}
 | 
| +  }, overrides: {
 | 
| +    'foo': 'any'
 | 
| +  }, result: {
 | 
| +    'myapp from root': '0.0.0',
 | 
| +    'foo': '0.0.0'
 | 
| +  });
 | 
| +}
 | 
| +
 | 
| +testResolve(String description, Map packages, {
 | 
| +    Map lockfile, Map overrides, Map result, FailMatcherBuilder error,
 | 
| +    int maxTries, bool useBleedingEdgeSdkVersion}) {
 | 
| +  _testResolve(test, description, packages, lockfile: lockfile,
 | 
| +      overrides: overrides, result: result, error: error, maxTries: maxTries,
 | 
|        useBleedingEdgeSdkVersion: useBleedingEdgeSdkVersion);
 | 
|  }
 | 
|  
 | 
| -solo_testResolve(description, packages, {
 | 
| -             lockfile, result, FailMatcherBuilder error, int maxTries,
 | 
| -             bool useBleedingEdgeSdkVersion}) {
 | 
| +solo_testResolve(String description, Map packages, {
 | 
| +    Map lockfile, Map overrides, Map result, FailMatcherBuilder error,
 | 
| +    int maxTries, bool useBleedingEdgeSdkVersion}) {
 | 
|    log.showSolver();
 | 
|    _testResolve(solo_test, description, packages, lockfile: lockfile,
 | 
| -      result: result, error: error, maxTries: maxTries,
 | 
| +      overrides: overrides, result: result, error: error, maxTries: maxTries,
 | 
|        useBleedingEdgeSdkVersion: useBleedingEdgeSdkVersion);
 | 
|  }
 | 
|  
 | 
|  _testResolve(void testFn(String description, Function body),
 | 
| -             description, packages, {
 | 
| -             lockfile, result, FailMatcherBuilder error, int maxTries,
 | 
| -             bool useBleedingEdgeSdkVersion}) {
 | 
| +    String description, Map packages, {
 | 
| +    Map lockfile, Map overrides, Map result, FailMatcherBuilder error,
 | 
| +    int maxTries, bool useBleedingEdgeSdkVersion}) {
 | 
|    if (maxTries == null) maxTries = 1;
 | 
|    if (useBleedingEdgeSdkVersion == null) useBleedingEdgeSdkVersion = false;
 | 
|  
 | 
| @@ -923,6 +1055,15 @@ _testResolve(void testFn(String description, Function body),
 | 
|        });
 | 
|      }
 | 
|  
 | 
| +    // Parse the overrides.
 | 
| +    var realOverrides = [];
 | 
| +    if (overrides != null) {
 | 
| +      overrides.forEach((spec, constraint) {
 | 
| +        realOverrides.add(parseSpec(spec).withConstraint(
 | 
| +            new VersionConstraint.parse(constraint)));
 | 
| +      });
 | 
| +    }
 | 
| +
 | 
|      // Make a version number like the continuous build's version.
 | 
|      var previousVersion = sdk.version;
 | 
|      if (useBleedingEdgeSdkVersion) {
 | 
| @@ -931,7 +1072,7 @@ _testResolve(void testFn(String description, Function body),
 | 
|  
 | 
|      // Resolve the versions.
 | 
|      var future = resolveVersions(cache.sources, root,
 | 
| -        lockFile: realLockFile);
 | 
| +        lockFile: realLockFile, overrides: realOverrides);
 | 
|  
 | 
|      var matcher;
 | 
|      if (result != null) {
 | 
| 
 |