Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
e5fb2fb0
Commit
e5fb2fb0
authored
Jun 23, 2016
by
Ian Hickson
Committed by
GitHub
Jun 23, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
An API for tracking software licenses. (#4711)
parent
bbf31cd3
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
530 additions
and
16 deletions
+530
-16
foundation.dart
packages/flutter/lib/foundation.dart
+1
-0
binding.dart
packages/flutter/lib/src/foundation/binding.dart
+6
-0
licenses.dart
packages/flutter/lib/src/foundation/licenses.dart
+264
-0
about.dart
packages/flutter/lib/src/material/about.dart
+62
-16
licenses_test.dart
packages/flutter/test/foundation/licenses_test.dart
+197
-0
No files found.
packages/flutter/lib/foundation.dart
View file @
e5fb2fb0
...
...
@@ -13,5 +13,6 @@ export 'src/foundation/assertions.dart';
export
'src/foundation/basic_types.dart'
;
export
'src/foundation/binding.dart'
;
export
'src/foundation/change_notifier.dart'
;
export
'src/foundation/licenses.dart'
;
export
'src/foundation/print.dart'
;
export
'src/foundation/synchronous_future.dart'
;
packages/flutter/lib/src/foundation/binding.dart
View file @
e5fb2fb0
...
...
@@ -11,6 +11,7 @@ import 'package:meta/meta.dart';
import
'assertions.dart'
;
import
'basic_types.dart'
;
import
'licenses.dart'
;
/// Signature for service extensions.
///
...
...
@@ -74,9 +75,14 @@ abstract class BindingBase {
/// `initInstances()`.
void
initInstances
()
{
assert
(!
_debugInitialized
);
LicenseRegistry
.
addLicense
(
_addLicenses
);
assert
(()
{
_debugInitialized
=
true
;
return
true
;
});
}
Iterable
<
LicenseEntry
>
_addLicenses
()
sync
*
{
// TODO(ianh): Populate the license registry.
}
/// Called when the binding is initialized, to register service
/// extensions.
///
...
...
packages/flutter/lib/src/foundation/licenses.dart
0 → 100644
View file @
e5fb2fb0
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/// Signature for callbacks passed to [LicenseRegistry.addLicense].
typedef
Iterable
<
LicenseEntry
>
LicenseEntryCollector
();
/// A string that represents one paragraph in a [LicenseEntry].
///
/// See [LicenseEntry.paragraphs].
class
LicenseParagraph
{
/// Creates a string for a license entry paragraph.
const
LicenseParagraph
(
this
.
text
,
this
.
indent
);
/// The text of the paragraph. Should not have any leading or trailing whitespace.
final
String
text
;
/// How many steps of indentation the paragraph has.
///
/// * 0 means the paragraph is not indented.
/// * 1 means the paragraph is indented one unit of indentation.
/// * 2 means the paragraph is indented two units of indentation.
///
/// ...and so forth.
///
/// In addition, the special value [centeredIndent] can be used to indicate
/// that rather than being indented, the paragraph is centered.
final
int
indent
;
// can be set to centeredIndent
/// A constant that represents "centered" alignment for [indent].
static
const
int
centeredIndent
=
-
1
;
}
/// A license that covers part of the application's software or assets, to show
/// in an interface such as the [LicensePage].
///
/// For optimal performance, [LicenseEntry] objects should only be created on
/// demand in [LicenseEntryCollector] callbacks passed to
/// [LicenseRegistry.addLicense].
abstract
class
LicenseEntry
{
/// Abstract const constructor. This constructor enables subclasses to provide
/// const constructors so that they can be used in const expressions.
const
LicenseEntry
();
/// Returns each paragraph of the license as a [LicenseParagraph], which
/// consists of a string and some formatting information. Paragraphs can
/// include newline characters, but this is discouraged as it results in
/// ugliness.
Iterable
<
LicenseParagraph
>
get
paragraphs
;
}
enum
_LicenseEntryWithLineBreaksParserState
{
beforeParagraph
,
inParagraph
}
/// Variant of [LicenseEntry] for licenses that separate paragraphs with blank
/// lines and that hard-wrap text within paragraphs. Lines that begin with one
/// or more space characters are also assumed to introduce new paragraphs,
/// unless they start with the same number of spaces as the previous line, in
/// which case it's assumed they are a continuation of an indented paragraph.
///
/// For example, the BSD license in this format could be encoded as follows:
///
/// ```dart
/// LicenseRegistry.addLicense(() {
/// yield new LicenseEntryWithLineBreaks('''
/// Copyright 2016 The Sample Authors. All rights reserved.
///
/// Redistribution and use in source and binary forms, with or without
/// modification, are permitted provided that the following conditions are
/// met:
///
/// * Redistributions of source code must retain the above copyright
/// notice, this list of conditions and the following disclaimer.
/// * Redistributions in binary form must reproduce the above
/// copyright notice, this list of conditions and the following disclaimer
/// in the documentation and/or other materials provided with the
/// distribution.
/// * Neither the name of Example Inc. nor the names of its
/// contributors may be used to endorse or promote products derived from
/// this software without specific prior written permission.
///
/// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
/// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
/// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
/// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
/// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
/// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
/// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
/// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
/// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
/// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
/// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''');
/// }
/// ```
///
/// This would result in a license with six [paragraphs], the third, fourth, and
/// fifth being indented one level.
class
LicenseEntryWithLineBreaks
extends
LicenseEntry
{
/// Create a license entry for a license whose text is hard-wrapped within
/// paragraphs and has paragraph breaks denoted by blank lines or with
/// indented text.
const
LicenseEntryWithLineBreaks
(
this
.
text
);
/// The text of the license.
///
/// The text will be split into paragraphs according to the following
/// conventions:
///
/// * Lines starting with a different number of space characters than the
/// previous line start a new paragraph, with those spaces removed.
/// * Blank lines start a new paragraph.
/// * Other line breaks are replaced by a single space character.
/// * Leading spaces on a line are removed.
///
/// For each paragraph, the algorithm attempts (using some rough heuristics)
/// to identify how indented the paragraph is, or whether it is centered.
final
String
text
;
@override
Iterable
<
LicenseParagraph
>
get
paragraphs
sync
*
{
int
lineStart
=
0
;
int
currentPosition
=
0
;
int
lastLineIndent
=
0
;
int
currentLineIndent
=
0
;
int
currentParagraphIndentation
;
_LicenseEntryWithLineBreaksParserState
state
=
_LicenseEntryWithLineBreaksParserState
.
beforeParagraph
;
List
<
String
>
lines
=
<
String
>[];
void
addLine
()
{
assert
(
lineStart
<
currentPosition
);
lines
.
add
(
text
.
substring
(
lineStart
,
currentPosition
));
}
LicenseParagraph
getParagraph
()
{
assert
(
lines
.
isNotEmpty
);
assert
(
currentParagraphIndentation
!=
null
);
final
LicenseParagraph
result
=
new
LicenseParagraph
(
lines
.
join
(
' '
),
currentParagraphIndentation
);
assert
(
result
.
text
.
trimLeft
()
==
result
.
text
);
assert
(
result
.
text
.
isNotEmpty
);
lines
.
clear
();
return
result
;
}
while
(
currentPosition
<
text
.
length
)
{
switch
(
state
)
{
case
_LicenseEntryWithLineBreaksParserState
.
beforeParagraph
:
assert
(
lineStart
==
currentPosition
);
switch
(
text
[
currentPosition
])
{
case
' '
:
lineStart
=
currentPosition
+
1
;
currentLineIndent
+=
1
;
state
=
_LicenseEntryWithLineBreaksParserState
.
beforeParagraph
;
break
;
case
'
\n
'
:
case
'
\
f'
:
if
(
lines
.
isNotEmpty
)
yield
getParagraph
();
lastLineIndent
=
0
;
currentLineIndent
=
0
;
currentParagraphIndentation
=
null
;
lineStart
=
currentPosition
+
1
;
state
=
_LicenseEntryWithLineBreaksParserState
.
beforeParagraph
;
break
;
case
'['
:
// This is a bit of a hack for the LGPL 2.1, which does something like this:
//
// [this is a
// single paragraph]
//
// ...near the top.
currentLineIndent
+=
1
;
continue
startParagraph
;
startParagraph:
default
:
if
(
lines
.
isNotEmpty
&&
currentLineIndent
>
lastLineIndent
)
{
yield
getParagraph
();
currentParagraphIndentation
=
null
;
}
// The following is a wild heuristic for guessing the indentation level.
// It happens to work for common variants of the BSD and LGPL licenses.
if
(
currentParagraphIndentation
==
null
)
{
if
(
currentLineIndent
>
10
)
currentParagraphIndentation
=
LicenseParagraph
.
centeredIndent
;
else
currentParagraphIndentation
=
currentLineIndent
~/
3
;
}
state
=
_LicenseEntryWithLineBreaksParserState
.
inParagraph
;
}
break
;
case
_LicenseEntryWithLineBreaksParserState
.
inParagraph
:
switch
(
text
[
currentPosition
])
{
case
'
\n
'
:
addLine
();
lastLineIndent
=
currentLineIndent
;
currentLineIndent
=
0
;
lineStart
=
currentPosition
+
1
;
state
=
_LicenseEntryWithLineBreaksParserState
.
beforeParagraph
;
break
;
case
'
\
f'
:
addLine
();
yield
getParagraph
();
lastLineIndent
=
0
;
currentLineIndent
=
0
;
currentParagraphIndentation
=
null
;
lineStart
=
currentPosition
+
1
;
state
=
_LicenseEntryWithLineBreaksParserState
.
beforeParagraph
;
break
;
default
:
state
=
_LicenseEntryWithLineBreaksParserState
.
inParagraph
;
}
break
;
}
currentPosition
+=
1
;
}
switch
(
state
)
{
case
_LicenseEntryWithLineBreaksParserState
.
beforeParagraph
:
if
(
lines
.
isNotEmpty
)
yield
getParagraph
();
break
;
case
_LicenseEntryWithLineBreaksParserState
.
inParagraph
:
addLine
();
yield
getParagraph
();
break
;
}
}
}
/// A registry for packages to add licenses to, so that they can be displayed
/// together in an interface such as the [LicensePage].
///
/// Packages should register their licenses using [addLicense]. User interfaces
/// that wish to show all the licenses can obtain them by calling [licenses].
class
LicenseRegistry
{
LicenseRegistry
.
_
();
static
List
<
LicenseEntryCollector
>
_collectors
;
/// Adds licenses to the registry.
///
/// To avoid actually manipulating the licenses unless strictly necessary,
/// licenses are added by adding a closure that returns a list of
/// [LicenseEntry] objects. The closure is only called if [licenses] is itself
/// called; in normal operation, if the user does not request to see the
/// licenses, the closure will not be called.
static
void
addLicense
(
LicenseEntryCollector
collector
)
{
_collectors
??=
<
LicenseEntryCollector
>[];
_collectors
.
add
(
collector
);
}
/// Returns the licenses that have been registered.
///
/// Each time the iterable returned by this function is called, the callbacks
/// registered with [addLicense] are called again, which is relatively
/// expensive. For this reason, consider immediately converting the results to
/// a list with [Iterable.toList].
static
Iterable
<
LicenseEntry
>
get
licenses
sync
*
{
if
(
_collectors
==
null
)
return
;
for
(
LicenseEntryCollector
collector
in
_collectors
)
yield
*
collector
();
}
}
\ No newline at end of file
packages/flutter/lib/src/material/about.dart
View file @
e5fb2fb0
...
...
@@ -301,7 +301,7 @@ class AboutDialog extends StatelessWidget {
///
/// To show a [LicensePage], use [showLicensePage].
// TODO(ianh): Mention the API for registering more licenses once it exists.
class
LicensePage
extends
State
less
Widget
{
class
LicensePage
extends
State
ful
Widget
{
/// Creates a page that shows licenses for software used by the application.
///
/// The arguments are all optional. The application name, if omitted, will be
...
...
@@ -337,27 +337,73 @@ class LicensePage extends StatelessWidget {
/// Defaults to the empty string.
final
String
applicationLegalese
;
@override
_LicensePageState
createState
()
=>
new
_LicensePageState
();
}
class
_LicensePageState
extends
State
<
LicensePage
>
{
List
<
Widget
>
_licenses
=
_initLicenses
();
static
List
<
Widget
>
_initLicenses
()
{
List
<
Widget
>
result
=
<
Widget
>[];
for
(
LicenseEntry
license
in
LicenseRegistry
.
licenses
)
{
bool
haveMargin
=
true
;
result
.
add
(
new
Padding
(
padding:
new
EdgeInsets
.
symmetric
(
vertical:
18.0
),
child:
new
Text
(
'🍀'
,
// That's U+1F340. Could also use U+2766 (❦) if U+1F340 doesn't work everywhere.
textAlign:
TextAlign
.
center
)
));
for
(
LicenseParagraph
paragraph
in
license
.
paragraphs
)
{
if
(
paragraph
.
indent
==
LicenseParagraph
.
centeredIndent
)
{
result
.
add
(
new
Padding
(
padding:
new
EdgeInsets
.
only
(
top:
haveMargin
?
0.0
:
16.0
),
child:
new
Text
(
paragraph
.
text
,
style:
new
TextStyle
(
fontWeight:
FontWeight
.
bold
),
textAlign:
TextAlign
.
center
)
));
}
else
{
assert
(
paragraph
.
indent
>=
0
);
result
.
add
(
new
Padding
(
padding:
new
EdgeInsets
.
only
(
top:
haveMargin
?
0.0
:
8.0
,
left:
16.0
*
paragraph
.
indent
),
child:
new
Text
(
paragraph
.
text
)
));
}
haveMargin
=
false
;
}
}
return
result
;
}
@override
Widget
build
(
BuildContext
context
)
{
final
String
name
=
applicationName
??
_defaultApplicationName
(
context
);
final
String
version
=
applicationVersion
??
_defaultApplicationVersion
(
context
);
final
String
name
=
config
.
applicationName
??
_defaultApplicationName
(
context
);
final
String
version
=
config
.
applicationVersion
??
_defaultApplicationVersion
(
context
);
final
List
<
Widget
>
contents
=
<
Widget
>[
new
Text
(
name
,
style:
Theme
.
of
(
context
).
textTheme
.
headline
,
textAlign:
TextAlign
.
center
),
new
Text
(
version
,
style:
Theme
.
of
(
context
).
textTheme
.
body1
,
textAlign:
TextAlign
.
center
),
new
Container
(
height:
18.0
),
new
Text
(
config
.
applicationLegalese
??
''
,
style:
Theme
.
of
(
context
).
textTheme
.
caption
,
textAlign:
TextAlign
.
center
),
new
Container
(
height:
18.0
),
new
Text
(
'Powered by Flutter'
,
style:
Theme
.
of
(
context
).
textTheme
.
body1
,
textAlign:
TextAlign
.
center
),
new
Container
(
height:
24.0
),
];
contents
.
addAll
(
_licenses
);
return
new
Scaffold
(
appBar:
new
AppBar
(
title:
new
Text
(
'Licenses'
)
),
body:
new
Block
(
padding:
new
EdgeInsets
.
symmetric
(
horizontal:
8.0
,
vertical:
12.0
),
children:
<
Widget
>[
new
Text
(
name
,
style:
Theme
.
of
(
context
).
textTheme
.
headline
,
textAlign:
TextAlign
.
center
),
new
Text
(
version
,
style:
Theme
.
of
(
context
).
textTheme
.
body1
,
textAlign:
TextAlign
.
center
),
new
Container
(
height:
18.0
),
new
Text
(
applicationLegalese
??
''
,
style:
Theme
.
of
(
context
).
textTheme
.
caption
,
textAlign:
TextAlign
.
center
),
new
Container
(
height:
18.0
),
new
Text
(
'Powered by Flutter'
,
style:
Theme
.
of
(
context
).
textTheme
.
body1
,
textAlign:
TextAlign
.
center
),
new
Container
(
height:
24.0
),
// TODO(ianh): Fill in the licenses from the API for registering more licenses once it exists.
new
Text
(
'<licenses will be automatically included here>'
,
style:
Theme
.
of
(
context
).
textTheme
.
caption
)
]
body:
new
DefaultTextStyle
(
style:
Theme
.
of
(
context
).
textTheme
.
caption
,
child:
new
LazyBlock
(
padding:
new
EdgeInsets
.
symmetric
(
horizontal:
8.0
,
vertical:
12.0
),
delegate:
new
LazyBlockChildren
(
children:
contents
)
)
)
);
}
...
...
packages/flutter/test/foundation/licenses_test.dart
0 → 100644
View file @
e5fb2fb0
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/foundation.dart'
;
import
'package:test/test.dart'
;
void
main
(
)
{
test
(
'LicenseEntryWithLineBreaks - most cases'
,
()
{
// There's some trailing spaces in this string.
// To avoid IDEs stripping them, I've escaped them as \u0020.
List
<
LicenseParagraph
>
paragraphs
=
new
LicenseEntryWithLineBreaks
(
'''
A
A
A
B
B
B
C
C
C
D
D
D
E
E
F
G
G
G
[H
H
H]
\
u0020
\
u0020
IJ
K
K
L
L L
L L
L L
L L
L L
M
M
\
u0020
\
u0020
\
u0020
M
\
u0020
\
u0020
\
u0020
\
u0020
N
O
O
P
QQQ
RR RRR RRRR RRRRR
R
S
T
U
V
W
X
\
u0020
\
u0020
\
u0020
\
u0020
\
u0020
\
u0020
Y'''
).
paragraphs
.
toList
();
int
index
=
0
;
expect
(
paragraphs
[
index
].
text
,
'A A A'
);
expect
(
paragraphs
[
index
].
indent
,
0
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'B B B'
);
expect
(
paragraphs
[
index
].
indent
,
0
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'C C C'
);
expect
(
paragraphs
[
index
].
indent
,
1
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'D D D'
);
expect
(
paragraphs
[
index
].
indent
,
LicenseParagraph
.
centeredIndent
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'E E'
);
expect
(
paragraphs
[
index
].
indent
,
0
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'F'
);
expect
(
paragraphs
[
index
].
indent
,
0
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'G G G'
);
expect
(
paragraphs
[
index
].
indent
,
0
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'[H H H]'
);
expect
(
paragraphs
[
index
].
indent
,
0
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'I'
);
expect
(
paragraphs
[
index
].
indent
,
0
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'J'
);
expect
(
paragraphs
[
index
].
indent
,
0
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'K K'
);
expect
(
paragraphs
[
index
].
indent
,
0
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'L L L L L L L L L L L'
);
expect
(
paragraphs
[
index
].
indent
,
0
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'M M M '
);
expect
(
paragraphs
[
index
].
indent
,
1
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'N'
);
expect
(
paragraphs
[
index
].
indent
,
0
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'O O'
);
expect
(
paragraphs
[
index
].
indent
,
0
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'P'
);
expect
(
paragraphs
[
index
].
indent
,
0
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'QQQ'
);
expect
(
paragraphs
[
index
].
indent
,
0
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'RR RRR RRRR RRRRR R'
);
expect
(
paragraphs
[
index
].
indent
,
0
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'S'
);
expect
(
paragraphs
[
index
].
indent
,
0
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'T'
);
expect
(
paragraphs
[
index
].
indent
,
1
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'U'
);
expect
(
paragraphs
[
index
].
indent
,
2
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'V'
);
expect
(
paragraphs
[
index
].
indent
,
3
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'W'
);
expect
(
paragraphs
[
index
].
indent
,
2
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'X'
);
expect
(
paragraphs
[
index
].
indent
,
2
);
index
+=
1
;
expect
(
paragraphs
[
index
].
text
,
'Y'
);
expect
(
paragraphs
[
index
].
indent
,
2
);
index
+=
1
;
expect
(
paragraphs
,
hasLength
(
index
));
});
test
(
'LicenseEntryWithLineBreaks - leading and trailing whitespace'
,
()
{
expect
(
new
LicenseEntryWithLineBreaks
(
'
\n\n
'
).
paragraphs
.
toList
(),
isEmpty
);
List
<
LicenseParagraph
>
paragraphs
;
paragraphs
=
new
LicenseEntryWithLineBreaks
(
'
\n
A
\n
'
).
paragraphs
.
toList
();
expect
(
paragraphs
[
0
].
text
,
'A'
);
expect
(
paragraphs
[
0
].
indent
,
0
);
expect
(
paragraphs
,
hasLength
(
1
));
paragraphs
=
new
LicenseEntryWithLineBreaks
(
'
\n\n\n
A
\n\n\n
'
).
paragraphs
.
toList
();
expect
(
paragraphs
[
0
].
text
,
'A'
);
expect
(
paragraphs
[
0
].
indent
,
0
);
expect
(
paragraphs
,
hasLength
(
1
));
});
test
(
'LicenseRegistry'
,
()
{
expect
(
LicenseRegistry
.
licenses
,
isEmpty
);
LicenseRegistry
.
addLicense
(()
{
return
<
LicenseEntry
>[
new
LicenseEntryWithLineBreaks
(
'A'
),
new
LicenseEntryWithLineBreaks
(
'B'
),
];
});
LicenseRegistry
.
addLicense
(()
{
return
<
LicenseEntry
>[
new
LicenseEntryWithLineBreaks
(
'C'
),
new
LicenseEntryWithLineBreaks
(
'D'
),
];
});
expect
(
LicenseRegistry
.
licenses
,
hasLength
(
4
));
List
<
LicenseEntry
>
licenses
=
LicenseRegistry
.
licenses
.
toList
();
expect
(
licenses
,
hasLength
(
4
));
expect
(
licenses
[
0
].
paragraphs
.
single
.
text
,
'A'
);
expect
(
licenses
[
1
].
paragraphs
.
single
.
text
,
'B'
);
expect
(
licenses
[
2
].
paragraphs
.
single
.
text
,
'C'
);
expect
(
licenses
[
3
].
paragraphs
.
single
.
text
,
'D'
);
});
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment