Skip to content

Commit b07cbe1

Browse files
committed
feat(nextcloud_test): Add Matcher for checking all WebDAV props are parsed
Signed-off-by: provokateurin <[email protected]>
1 parent a11cdd3 commit b07cbe1

File tree

3 files changed

+76
-0
lines changed

3 files changed

+76
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export 'src/fixtures.dart' hide appendFixture;
2+
export 'src/matchers/webdav_props.dart';
23
export 'src/models/nextcloud_tester.dart';
34
export 'src/presets.dart';
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import 'package:built_collection/built_collection.dart';
2+
import 'package:collection/collection.dart';
3+
import 'package:http/http.dart' as http;
4+
// ignore: implementation_imports
5+
import 'package:matcher/src/expect/async_matcher.dart';
6+
import 'package:nextcloud/webdav.dart';
7+
import 'package:nextcloud_test/src/models/models.dart';
8+
import 'package:test/test.dart';
9+
import 'package:xml/xml.dart';
10+
11+
class _ContainsAllAvailableProps extends AsyncMatcher {
12+
_ContainsAllAvailableProps(
13+
this.tester,
14+
this.uri,
15+
);
16+
17+
final NextcloudTester tester;
18+
final PathUri uri;
19+
20+
@override
21+
Description describe(Description description) {
22+
return description;
23+
}
24+
25+
@override
26+
Future<String?> matchAsync(dynamic item) async {
27+
if (item is! XmlElement) {
28+
return 'Expected XmlElement, got ${item.runtimeType}.';
29+
}
30+
31+
final parsedProps = _getMultistatusPropNames(item);
32+
if (parsedProps.isEmpty) {
33+
return 'Parsed props were empty';
34+
}
35+
36+
final streamedResponse = await tester.client.webdav.httpClient.send(tester.client.webdav.propfind_Request(uri));
37+
if (streamedResponse.statusCode != 207) {
38+
return 'PROPFIND response status code was not 207';
39+
}
40+
final rawResponse = await http.Response.fromStream(streamedResponse);
41+
42+
final expectedProps = _getMultistatusPropNames(XmlDocument.parse(rawResponse.body).rootElement);
43+
if (expectedProps.isEmpty) {
44+
return 'Expected props were empty';
45+
}
46+
47+
if (parsedProps != expectedProps) {
48+
return 'Missing props: ${expectedProps.where((p) => !parsedProps.contains(p)).join(', ')}';
49+
}
50+
51+
return null;
52+
}
53+
54+
BuiltList<String> _getMultistatusPropNames(XmlElement root) {
55+
return root.firstElementChild!.childElements
56+
.singleWhere(
57+
(node) =>
58+
node.name.local == 'propstat' &&
59+
node.childElements.singleWhere((node) => node.name.local == 'status').innerText.contains('200 OK'),
60+
)
61+
.childElements
62+
.singleWhere((node) => node.name.local == 'prop')
63+
.childElements
64+
.map((el) => '{${el.name.namespaceUri}}${el.name.local}')
65+
.toList()
66+
.sorted()
67+
.toBuiltList();
68+
}
69+
}
70+
71+
/// Checks that all props have been parsed, by comparing them to a raw PROPFIND response of a request to [uri].
72+
Matcher containsAllAvailableProps(NextcloudTester tester, PathUri uri) => _ContainsAllAvailableProps(tester, uri);

packages/nextcloud/packages/nextcloud_test/pubspec.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ environment:
77

88
dependencies:
99
built_collection: ^5.1.1
10+
collection: ^1.0.0
1011
cookie_store:
1112
git:
1213
url: https://github.com/nextcloud/neon
@@ -17,6 +18,7 @@ dependencies:
1718
git:
1819
url: https://github.com/nextcloud/neon
1920
path: packages/interceptor_http_client
21+
matcher: ^0.12.0
2022
meta: ^1.0.0
2123
nextcloud: ^8.1.0
2224
path: ^1.9.0
@@ -25,6 +27,7 @@ dependencies:
2527
test_api: ^0.7.0
2628
universal_io: ^2.0.0
2729
version: ^3.0.0
30+
xml: ^6.0.0
2831

2932
dev_dependencies:
3033
neon_lints:

0 commit comments

Comments
 (0)