Merge pull request #106 from yjbanov/init-clientId

make clientId available immediately
diff --git a/lib/src/usage_impl.dart b/lib/src/usage_impl.dart
index 3f5eee4..cb92972 100644
--- a/lib/src/usage_impl.dart
+++ b/lib/src/usage_impl.dart
@@ -200,13 +200,7 @@
   }
 
   @override
-  String get clientId => properties['clientId'];
-
-  void _initClientId() {
-    if (clientId == null) {
-      properties['clientId'] = new Uuid().generateV4();
-    }
-  }
+  String get clientId => properties['clientId'] ??= new Uuid().generateV4();
 
   /**
    * Send raw data to analytics. Callers should generally use one of the typed
@@ -227,8 +221,6 @@
     if (!enabled) return new Future.value();
 
     if (_bucket.removeDrop()) {
-      _initClientId();
-
       _variableMap.forEach((key, value) {
         args[key] = value;
       });
diff --git a/test/usage_impl_test.dart b/test/usage_impl_test.dart
index 267029c..1952237 100644
--- a/test/usage_impl_test.dart
+++ b/test/usage_impl_test.dart
@@ -62,6 +62,28 @@
       mock.sendScreenView('baz');
       return mock.waitForLastPing(timeout: new Duration(milliseconds: 100));
     });
+
+    group('clientId', () {
+      test('is available immediately', () {
+        AnalyticsImplMock mock = createMock();
+        expect(mock.clientId, isNotEmpty);
+      });
+
+      test('is memoized', () {
+        AnalyticsImplMock mock = createMock();
+        final value1 = mock.clientId;
+        final value2 = mock.clientId;
+        expect(value1, isNotEmpty);
+        expect(value1, value2);
+      });
+
+      test('is stored in properties', () {
+        AnalyticsImplMock mock = createMock();
+        expect(mock.properties['clientId'], isNull);
+        final value = mock.clientId;
+        expect(mock.properties['clientId'], value);
+      });
+    });
   });
 
   group('postEncode', () {