From 65b7e647e53310c7125f4f0a031eb85427d4f095 Mon Sep 17 00:00:00 2001
From: "nweiz@google.com" <nweiz@google.com>
Date: Wed, 12 Dec 2012 00:54:17 +0000
Subject: [PATCH] Add a validator that checks that the lib directory is not
 empty.

BUG=7045

Review URL: https://codereview.chromium.org//11543006

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge@16010 260f80e4-7a28-3924-810f-c04153c831b5
---
 lib/src/validator.dart     |  2 ++
 lib/src/validator/lib.dart | 43 ++++++++++++++++++++++++++++++++++
 test/oauth2_test.dart      |  7 +-----
 test/pub_lish_test.dart    |  7 +-----
 test/test_pub.dart         |  9 +++++++
 test/validator_test.dart   | 48 +++++++++++++++++++++++++++++++-------
 6 files changed, 96 insertions(+), 20 deletions(-)
 create mode 100644 lib/src/validator/lib.dart

diff --git a/lib/src/validator.dart b/lib/src/validator.dart
index dea568fd..3e491a93 100644
--- a/lib/src/validator.dart
+++ b/lib/src/validator.dart
@@ -9,6 +9,7 @@ import 'log.dart' as log;
 import 'io.dart';
 import 'system_cache.dart';
 import 'utils.dart';
+import 'validator/lib.dart';
 import 'validator/license.dart';
 import 'validator/name.dart';
 import 'validator/pubspec_field.dart';
@@ -40,6 +41,7 @@ abstract class Validator {
   static Future<Pair<List<String>, List<String>>> runAll(
       Entrypoint entrypoint) {
     var validators = [
+      new LibValidator(entrypoint),
       new LicenseValidator(entrypoint),
       new NameValidator(entrypoint),
       new PubspecFieldValidator(entrypoint)
diff --git a/lib/src/validator/lib.dart b/lib/src/validator/lib.dart
new file mode 100644
index 00000000..64f44c63
--- /dev/null
+++ b/lib/src/validator/lib.dart
@@ -0,0 +1,43 @@
+// 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 lib_validator;
+
+import 'dart:io';
+
+import '../entrypoint.dart';
+import '../io.dart';
+import '../system_cache.dart';
+import '../utils.dart';
+import '../validator.dart';
+
+// TODO(nweiz): When issue 7196 is fixed, complain about non-Dart files in lib.
+/// A validator that checks that libraries in "lib/" (and not "lib/src/") exist
+/// and are well-formed.
+class LibValidator extends Validator {
+  LibValidator(Entrypoint entrypoint)
+    : super(entrypoint);
+
+  Future validate() {
+    var libDir = join(entrypoint.root.dir, "lib");
+    return dirExists(libDir).chain((libDirExists) {
+      if (!libDirExists) {
+        errors.add('Your package must have a "lib/" directory so users have '
+            'something to import.');
+        return new Future.immediate(null);
+      }
+
+      return listDir(libDir).transform((files) {
+        files = files.map((file) => relativeTo(file, libDir));
+        if (files.isEmpty) {
+          errors.add('The "lib/" directory may not be empty so users have '
+              'something to import');
+        } else if (files.length == 1 && files.first == "src") {
+          errors.add('The "lib/" directory must contain something other than '
+              '"src/" so users have something to import');
+        }
+      });
+    });
+  }
+}
diff --git a/test/oauth2_test.dart b/test/oauth2_test.dart
index fdbf92bd..32e4a75a 100644
--- a/test/oauth2_test.dart
+++ b/test/oauth2_test.dart
@@ -15,12 +15,7 @@ import '../../pub/io.dart';
 import '../../pub/utils.dart';
 
 main() {
-  setUp(() {
-    dir(appPath, [
-      libPubspec("test_pkg", "1.0.0"),
-      file("LICENSE", "Eh, do what you want.")
-    ]).scheduleCreate();
-  });
+  setUp(() => normalPackage.scheduleCreate());
 
   test('with no credentials.json, authenticates and saves credentials.json',
       () {
diff --git a/test/pub_lish_test.dart b/test/pub_lish_test.dart
index 58f6a198..a947601d 100644
--- a/test/pub_lish_test.dart
+++ b/test/pub_lish_test.dart
@@ -47,12 +47,7 @@ void handleUpload(ScheduledServer server) {
 }
 
 main() {
-  setUp(() {
-    dir(appPath, [
-      libPubspec("test_pkg", "1.0.0"),
-      file("LICENSE", "Eh, do what you want.")
-    ]).scheduleCreate();
-  });
+  setUp(() => normalPackage.scheduleCreate());
 
   test('archives and uploads a package', () {
     var server = new ScheduledServer();
diff --git a/test/test_pub.dart b/test/test_pub.dart
index 806ce3ee..aa8e8797 100644
--- a/test/test_pub.dart
+++ b/test/test_pub.dart
@@ -222,6 +222,15 @@ void servePackages(List<Map> pubspecs) {
 /** Converts [value] into a YAML string. */
 String yaml(value) => JSON.stringify(value);
 
+/// Describes a package that passes all validation.
+Descriptor get normalPackage => dir(appPath, [
+  libPubspec("test_pkg", "1.0.0"),
+  file("LICENSE", "Eh, do what you want."),
+  dir("lib", [
+    file("test_pkg.dart", "int i = 1;")
+  ])
+]);
+
 /**
  * Describes a file named `pubspec.yaml` with the given YAML-serialized
  * [contents], which should be a serializable object.
diff --git a/test/validator_test.dart b/test/validator_test.dart
index e5005bfb..d9877eb4 100644
--- a/test/validator_test.dart
+++ b/test/validator_test.dart
@@ -12,6 +12,7 @@ import '../../../pkg/unittest/lib/unittest.dart';
 import '../../pub/entrypoint.dart';
 import '../../pub/io.dart';
 import '../../pub/validator.dart';
+import '../../pub/validator/lib.dart';
 import '../../pub/validator/license.dart';
 import '../../pub/validator/name.dart';
 import '../../pub/validator/pubspec_field.dart';
@@ -28,19 +29,16 @@ void expectValidationWarning(ValidatorCreator fn) {
   expectLater(schedulePackageValidation(fn), pairOf(isEmpty, isNot(isEmpty)));
 }
 
-Validator pubspecField(Entrypoint entrypoint) =>
-  new PubspecFieldValidator(entrypoint);
+Validator lib(Entrypoint entrypoint) => new LibValidator(entrypoint);
 
 Validator license(Entrypoint entrypoint) => new LicenseValidator(entrypoint);
 
 Validator name(Entrypoint entrypoint) => new NameValidator(entrypoint);
 
-void scheduleNormalPackage() {
-  dir(appPath, [
-    libPubspec("test_pkg", "1.0.0"),
-    file("LICENSE", "Eh, do what you want.")
-  ]).scheduleCreate();
-}
+Validator pubspecField(Entrypoint entrypoint) =>
+  new PubspecFieldValidator(entrypoint);
+
+void scheduleNormalPackage() => normalPackage.scheduleCreate();
 
 main() {
   group('should consider a package valid if it', () {
@@ -93,6 +91,17 @@ main() {
       expectNoValidationError(name);
       run();
     });
+
+    test('has a non-Dart file in lib', () {
+      dir(appPath, [
+        libPubspec("test_pkg", "1.0.0"),
+        dir("lib", [
+          file("thing.txt", "woo hoo")
+        ])
+      ]).scheduleCreate();
+      expectNoValidationError(lib);
+      run();
+    });
   });
 
   group('should consider a package invalid if it', () {
@@ -242,5 +251,28 @@ main() {
       expectValidationError(name);
       run();
     });
+
+    test('has no lib directory', () {
+      dir(join(appPath, "lib")).scheduleDelete();
+      expectValidationError(lib);
+      run();
+    });
+
+    test('has an empty lib directory', () {
+      file(join(appPath, "lib", "test_pkg.dart"), '').scheduleDelete();
+      expectValidationError(lib);
+      run();
+    });
+
+    test('has a lib directory containing only src', () {
+      file(join(appPath, "lib", "test_pkg.dart"), '').scheduleDelete();
+      dir(appPath, [
+        dir("lib", [
+          dir("src", [file("test_pkg.dart", "int i = 0;")])
+        ])
+      ]).scheduleCreate();
+      expectValidationError(lib);
+      run();
+    });
   });
 }
-- 
GitLab