Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

[path_provider] Fix handling of null application ID #4606

Merged
merged 2 commits into from
Dec 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/path_provider/path_provider_linux/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 2.1.4

* Fixes `getApplicationSupportPath` handling of applications where the
application ID is not set.

## 2.1.3

* Change getApplicationSupportPath from using executable name to application ID (if provided).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:meta/meta.dart';

// GApplication* g_application_get_default();
typedef _GApplicationGetDefaultC = IntPtr Function();
Expand All @@ -13,30 +14,65 @@ typedef _GApplicationGetDefaultDart = int Function();
typedef _GApplicationGetApplicationIdC = Pointer<Utf8> Function(IntPtr);
typedef _GApplicationGetApplicationIdDart = Pointer<Utf8> Function(int);

/// Interface for interacting with libgio.
@visibleForTesting
class GioUtils {
/// Creates a default instance that uses the real libgio.
GioUtils() {
try {
_gio = DynamicLibrary.open('libgio-2.0.so');
} on ArgumentError {
_gio = null;
}
}

DynamicLibrary? _gio;

/// True if libgio was opened successfully.
bool get libraryIsPresent => _gio != null;

/// Wraps `g_application_get_default`.
int gApplicationGetDefault() {
if (_gio == null) {
return 0;
}
final _GApplicationGetDefaultDart getDefault = _gio!
.lookupFunction<_GApplicationGetDefaultC, _GApplicationGetDefaultDart>(
'g_application_get_default');
return getDefault();
}

/// Wraps g_application_get_application_id.
Pointer<Utf8> gApplicationGetApplicationId(int app) {
if (_gio == null) {
return nullptr;
}
final _GApplicationGetApplicationIdDart gApplicationGetApplicationId = _gio!
.lookupFunction<_GApplicationGetApplicationIdC,
_GApplicationGetApplicationIdDart>(
'g_application_get_application_id');
return gApplicationGetApplicationId(app);
}
}

/// Allows overriding the default GioUtils instance with a fake for testing.
@visibleForTesting
GioUtils? gioUtilsOverride;

/// Gets the application ID for this app.
String? getApplicationId() {
DynamicLibrary gio;
try {
gio = DynamicLibrary.open('libgio-2.0.so');
} on ArgumentError {
final GioUtils gio = gioUtilsOverride ?? GioUtils();
if (!gio.libraryIsPresent) {
return null;
}
final _GApplicationGetDefaultDart gApplicationGetDefault =
gio.lookupFunction<_GApplicationGetDefaultC, _GApplicationGetDefaultDart>(
'g_application_get_default');
final int app = gApplicationGetDefault();

final int app = gio.gApplicationGetDefault();
if (app == 0) {
return null;
}

final _GApplicationGetApplicationIdDart gApplicationGetApplicationId =
gio.lookupFunction<_GApplicationGetApplicationIdC,
_GApplicationGetApplicationIdDart>(
'g_application_get_application_id');
final Pointer<Utf8> appId = gApplicationGetApplicationId(app);
if (appId == null) {
final Pointer<Utf8> appId = gio.gApplicationGetApplicationId(app);
if (appId == null || appId == nullptr) {
return null;
}

return appId.toDartString();
}
3 changes: 2 additions & 1 deletion packages/path_provider/path_provider_linux/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: path_provider_linux
description: Linux implementation of the path_provider plugin
repository: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_linux
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22
version: 2.1.3
version: 2.1.4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember even for @VisibleForTesting API updates, we need to bump minor? (I might be wrong)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file that I added the new content to shouldn't be exported. I just wanted to be extra-obvious about it being test-only.


environment:
sdk: ">=2.12.0 <3.0.0"
Expand All @@ -19,6 +19,7 @@ dependencies:
ffi: ^1.1.2
flutter:
sdk: flutter
meta: ^1.3.0
path: ^1.8.0
path_provider_platform_interface: ^2.0.0
xdg_directories: ^0.2.0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2013 The Flutter 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 'dart:ffi';

import 'package:ffi/ffi.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:path_provider_linux/src/get_application_id_real.dart';

class _FakeGioUtils implements GioUtils {
int? application;
Pointer<Utf8>? applicationId;

@override
bool libraryIsPresent = false;

@override
int gApplicationGetDefault() => application!;

@override
Pointer<Utf8> gApplicationGetApplicationId(int app) => applicationId!;
}

void main() {
late _FakeGioUtils fakeGio;

setUp(() {
fakeGio = _FakeGioUtils();
gioUtilsOverride = fakeGio;
});

tearDown(() {
gioUtilsOverride = null;
});

test('returns null if libgio is not available', () {
expect(getApplicationId(), null);
});

test('returns null if g_paplication_get_default returns 0', () {
fakeGio.libraryIsPresent = true;
fakeGio.application = 0;
expect(getApplicationId(), null);
});

test('returns null if g_application_get_application_id returns nullptr', () {
fakeGio.libraryIsPresent = true;
fakeGio.application = 1;
fakeGio.applicationId = nullptr;
expect(getApplicationId(), null);
});

test('returns value if g_application_get_application_id returns a value', () {
fakeGio.libraryIsPresent = true;
fakeGio.application = 1;
const String id = 'foo';
final Pointer<Utf8> idPtr = id.toNativeUtf8();
fakeGio.applicationId = idPtr;
expect(getApplicationId(), id);
calloc.free(idPtr);
});
}