Some checks failed
Security / Security check (push) Failing after 2s
The store detail sheet now carries a data-source block for source.* modules: publisher, upstream url, the terms in plain words, and any attribution the operator has to carry with the output. It sits above maintainers and above the install button, because it is a decision input rather than a footnote. The values are selectable: compliance notes get written by copying, not retyping. A note names whose terms these are, so nobody reads them as the module's own licence. Four guards, including that an empty attribution renders no empty row. Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
85 lines
3.1 KiB
Dart
85 lines
3.1 KiB
Dart
// Guards for the data-provenance block in the store detail sheet.
|
|
//
|
|
// The rule it protects (docs/architecture/store-format.md): the terms
|
|
// of the material a source module fetches are separate from the
|
|
// module's own licence, and an operator must see them before the
|
|
// install button, not in a README afterwards.
|
|
|
|
import 'package:chain_studio/data/hub.dart';
|
|
import 'package:chain_studio/l10n/app_localizations.dart';
|
|
import 'package:chain_studio/pages/store.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
Widget _host(Widget child) => MaterialApp(
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
locale: const Locale('de'),
|
|
home: Scaffold(body: SingleChildScrollView(child: child)),
|
|
);
|
|
|
|
void main() {
|
|
const bund = DataProvenance(
|
|
name: 'gesetze-im-internet.de (BMJ / juris GmbH)',
|
|
url: 'https://www.gesetze-im-internet.de/',
|
|
license: 'Amtliches Werk (§ 5 UrhG), gemeinfrei',
|
|
attribution: 'Quelle: gesetze-im-internet.de (Bundesministerium der Justiz)',
|
|
);
|
|
|
|
testWidgets('publisher, terms and attribution are all shown',
|
|
(tester) async {
|
|
await tester.pumpWidget(_host(const StoreDataSourceSection(source: bund)));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text(bund.name), findsOneWidget);
|
|
expect(find.text(bund.url), findsOneWidget);
|
|
expect(find.text(bund.license), findsOneWidget);
|
|
expect(find.text(bund.attribution), findsOneWidget,
|
|
reason: 'an attribution duty must be visible before installing');
|
|
});
|
|
|
|
testWidgets('the attribution row is omitted when none is required',
|
|
(tester) async {
|
|
const noAttribution = DataProvenance(
|
|
name: 'Vom Betreiber gepflegter Metadaten-Katalog',
|
|
url: '',
|
|
license: 'Katalog des Betreibers',
|
|
attribution: '',
|
|
);
|
|
await tester
|
|
.pumpWidget(_host(const StoreDataSourceSection(source: noAttribution)));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text(noAttribution.name), findsOneWidget);
|
|
final l = AppLocalizations.of(
|
|
tester.element(find.byType(StoreDataSourceSection)),
|
|
)!;
|
|
expect(find.text(l.storeDataSourceAttribution), findsNothing,
|
|
reason: 'an empty attribution must not render an empty row');
|
|
});
|
|
|
|
testWidgets('the terms are selectable so they can be copied',
|
|
(tester) async {
|
|
await tester.pumpWidget(_host(const StoreDataSourceSection(source: bund)));
|
|
await tester.pumpAndSettle();
|
|
|
|
// Compliance notes get written by copying, not retyping.
|
|
expect(
|
|
find.byWidgetPredicate(
|
|
(w) => w is SelectableText && w.data == bund.attribution,
|
|
),
|
|
findsOneWidget,
|
|
);
|
|
});
|
|
|
|
testWidgets('the note says whose terms these are', (tester) async {
|
|
await tester.pumpWidget(_host(const StoreDataSourceSection(source: bund)));
|
|
await tester.pumpAndSettle();
|
|
|
|
final l = AppLocalizations.of(
|
|
tester.element(find.byType(StoreDataSourceSection)),
|
|
)!;
|
|
// Without this line an operator reads the terms as the module's.
|
|
expect(find.text(l.storeDataSourceNote), findsOneWidget);
|
|
});
|
|
}
|