Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ class UsercentricsPlugin : FlutterPlugin,
ClearUserSessionBridge(),
GetGPPDataBridge(),
GetGPPStringBridge(),
SetGPPConsentBridge()
SetGPPConsentBridge(),
GetDpsMetadataBridge()
).associateBy { it.name }
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.usercentrics.sdk.flutter.bridge

import com.usercentrics.sdk.flutter.api.FlutterMethodCall
import com.usercentrics.sdk.flutter.api.FlutterResult
import com.usercentrics.sdk.flutter.api.UsercentricsProxy
import com.usercentrics.sdk.flutter.api.UsercentricsProxySingleton

internal class GetDpsMetadataBridge(
private val usercentrics: UsercentricsProxy = UsercentricsProxySingleton
) : MethodBridge {

override val name: String
get() = "getDpsMetadata"

override fun invoke(call: FlutterMethodCall, result: FlutterResult) {
assert(name == call.method)
val templateId = call.arguments as String
result.success(usercentrics.instance.getDpsMetadata(templateId))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.usercentrics.sdk.flutter.bridge

import com.usercentrics.sdk.UsercentricsSDK
import com.usercentrics.sdk.flutter.api.FakeFlutterMethodCall
import com.usercentrics.sdk.flutter.api.FakeFlutterResult
import com.usercentrics.sdk.flutter.api.FakeUsercentricsProxy
import com.usercentrics.sdk.flutter.mock.GetDpsMetadataMock
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import org.junit.Assert.assertEquals
import org.junit.Assert.assertThrows
import org.junit.Test

class GetDpsMetadataBridgeTest {

@Test
fun testName() {
val instance = GetDpsMetadataBridge(FakeUsercentricsProxy())
assertEquals("getDpsMetadata", instance.name)
}

@Test
fun testInvokeWithOtherName() {
val instance = GetDpsMetadataBridge(FakeUsercentricsProxy())
val call = FakeFlutterMethodCall(method = "otherName", arguments = null)

assertThrows(AssertionError::class.java) {
instance.invoke(call, FakeFlutterResult())
}
}

@Test
fun testInvoke() {
val usercentricsSDK = mockk<UsercentricsSDK>()
every { usercentricsSDK.getDpsMetadata(GetDpsMetadataMock.templateId) }.returns(GetDpsMetadataMock.fake)
val usercentricsProxy = FakeUsercentricsProxy(usercentricsSDK)
val instance = GetDpsMetadataBridge(usercentricsProxy)
val result = FakeFlutterResult()

instance.invoke(GetDpsMetadataMock.call, result)

verify(exactly = 1) { usercentricsSDK.getDpsMetadata(GetDpsMetadataMock.templateId) }

assertEquals(1, result.successCount)
assertEquals(GetDpsMetadataMock.expected, result.successResultArgument)
}

@Test
fun testInvokeReturnsNull() {
val usercentricsSDK = mockk<UsercentricsSDK>()
every { usercentricsSDK.getDpsMetadata(any()) }.returns(null)
val usercentricsProxy = FakeUsercentricsProxy(usercentricsSDK)
val instance = GetDpsMetadataBridge(usercentricsProxy)
val result = FakeFlutterResult()
val call = FakeFlutterMethodCall(method = "getDpsMetadata", arguments = "unknownTemplate")

instance.invoke(call, result)

verify(exactly = 1) { usercentricsSDK.getDpsMetadata("unknownTemplate") }

assertEquals(1, result.successCount)
assertEquals(null, result.successResultArgument)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.usercentrics.sdk.flutter.mock

import com.usercentrics.sdk.flutter.api.FakeFlutterMethodCall

internal object GetDpsMetadataMock {

const val templateId = "templateId123"

val fake: Map<String, Any> = mapOf(
"key" to "value",
"count" to 42
)

val call = FakeFlutterMethodCall(method = "getDpsMetadata", arguments = templateId)
val expected: Map<String, Any> = mapOf(
"key" to "value",
"count" to 42
)
}
19 changes: 19 additions & 0 deletions ios/Classes/Bridge/GetDpsMetadataBridge.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Usercentrics

struct GetDpsMetadataBridge : MethodBridge {

let name: String = "getDpsMetadata"
let usercentrics: UsercentricsProxyProtocol

func invoke(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
assert(call.method == name)
guard let templateId = call.arguments as? String else {
result(FlutterError(code: "usercentrics_flutter_getDpsMetadata_error",
message: "Invalid Parameter",
details: nil ))
return
}

result(usercentrics.shared.getDpsMetadata(templateId: templateId))
}
}
3 changes: 2 additions & 1 deletion ios/Classes/SwiftUsercentricsPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ public class SwiftUsercentricsPlugin: NSObject, FlutterPlugin {
ClearUserSessionBridge(usercentrics: usercentrics),
GetGPPDataBridge(usercentrics: usercentrics),
GetGPPStringBridge(usercentrics: usercentrics),
SetGPPConsentBridge(usercentrics: usercentrics)
SetGPPConsentBridge(usercentrics: usercentrics),
GetDpsMetadataBridge(usercentrics: usercentrics)
]
return bridges.reduce([String : MethodBridge]()) { dict, value in
var dict = dict
Expand Down
1 change: 1 addition & 0 deletions lib/src/internal/bridge/bridge.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ export 'clear_user_session_bridge.dart';
export 'get_gpp_data_bridge.dart';
export 'get_gpp_string_bridge.dart';
export 'set_gpp_consent_bridge.dart';
export 'get_dps_metadata_bridge.dart';
25 changes: 25 additions & 0 deletions lib/src/internal/bridge/get_dps_metadata_bridge.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import 'package:flutter/services.dart';

abstract class GetDpsMetadataBridge {
const GetDpsMetadataBridge();

Future<Map<String, dynamic>?> invoke({
required MethodChannel channel,
required String templateId,
});
}

class MethodChannelGetDpsMetadata extends GetDpsMetadataBridge {
const MethodChannelGetDpsMetadata();

static const String _name = 'getDpsMetadata';

@override
Future<Map<String, dynamic>?> invoke({
required MethodChannel channel,
required String templateId,
}) async {
final result = await channel.invokeMethod<Map?>(_name, templateId);
return result?.cast<String, dynamic>();
}
}
15 changes: 14 additions & 1 deletion lib/src/internal/platform/method_channel_usercentrics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ class MethodChannelUsercentrics extends UsercentricsPlatform {
this.clearUserSessionBridge = const MethodChannelClearUserSession(),
this.getGPPDataBridge = const MethodChannelGetGPPData(),
this.getGPPStringBridge = const MethodChannelGetGPPString(),
this.setGPPConsentBridge = const MethodChannelSetGPPConsent()});
this.setGPPConsentBridge = const MethodChannelSetGPPConsent(),
this.getDpsMetadataBridge = const MethodChannelGetDpsMetadata()});

static const MethodChannel _channel = MethodChannel('usercentrics');
static const EventChannel _gppSectionChangeEventChannel =
Expand Down Expand Up @@ -71,6 +72,7 @@ class MethodChannelUsercentrics extends UsercentricsPlatform {
final GetGPPDataBridge getGPPDataBridge;
final GetGPPStringBridge getGPPStringBridge;
final SetGPPConsentBridge setGPPConsentBridge;
final GetDpsMetadataBridge getDpsMetadataBridge;

@visibleForTesting
Completer<Object?>? isReadyCompleter;
Expand Down Expand Up @@ -379,6 +381,17 @@ class MethodChannelUsercentrics extends UsercentricsPlatform {
);
}

@override
Future<Map<String, dynamic>?> getDpsMetadata({
required String templateId,
}) async {
await _ensureIsReady();
return await getDpsMetadataBridge.invoke(
channel: _channel,
templateId: templateId,
);
}

@override
Stream<GppSectionChangePayload> get onGppSectionChange {
return _gppSectionChangeEventChannel
Expand Down
4 changes: 4 additions & 0 deletions lib/src/platform/usercentrics_platform.dart
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,8 @@ abstract class UsercentricsPlatform {
});

Stream<GppSectionChangePayload> get onGppSectionChange;

Future<Map<String, dynamic>?> getDpsMetadata({
required String templateId,
});
}
8 changes: 8 additions & 0 deletions lib/src/usercentrics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -240,4 +240,12 @@ class Usercentrics {
/// Stream of GPP section change events.
static Stream<GppSectionChangePayload> get onGppSectionChange =>
_delegate.onGppSectionChange;

/// Get the DPS metadata for a given template ID.
/// Returns null if the templateId is not found, an empty map if metadata is absent/empty,
/// and a parsed map for valid JSON metadata.
static Future<Map<String, dynamic>?> getDpsMetadata({
required String templateId,
}) =>
_delegate.getDpsMetadata(templateId: templateId);
}
76 changes: 76 additions & 0 deletions test/internal/bridge/get_dps_metadata_bridge_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:usercentrics_sdk/src/internal/bridge/bridge.dart';

void main() {
const MethodChannel channel = MethodChannel('usercentrics');
TestWidgetsFlutterBinding.ensureInitialized();

tearDown(() async {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(channel, null);
});

test('invoke returns map', () async {
int callCounter = 0;
MethodCall? receivedCall;

TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(channel, (MethodCall methodCall) async {
callCounter++;
receivedCall = methodCall;
return <String, dynamic>{'key': 'value', 'count': 42};
});

const instance = MethodChannelGetDpsMetadata();

final result =
await instance.invoke(channel: channel, templateId: 'templateId123');

expect(callCounter, 1);
expect(receivedCall?.method, 'getDpsMetadata');
expect(receivedCall?.arguments, 'templateId123');
expect(result, {'key': 'value', 'count': 42});
});

test('invoke returns null', () async {
int callCounter = 0;
MethodCall? receivedCall;

TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(channel, (MethodCall methodCall) async {
callCounter++;
receivedCall = methodCall;
return null;
});

const instance = MethodChannelGetDpsMetadata();

final result =
await instance.invoke(channel: channel, templateId: 'unknownTemplate');

expect(callCounter, 1);
expect(receivedCall?.method, 'getDpsMetadata');
expect(receivedCall?.arguments, 'unknownTemplate');
expect(result, isNull);
});

test('invoke returns empty map', () async {
int callCounter = 0;

TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(channel, (MethodCall methodCall) async {
callCounter++;
return <String, dynamic>{};
});

const instance = MethodChannelGetDpsMetadata();

final result =
await instance.invoke(channel: channel, templateId: 'templateId456');

expect(callCounter, 1);
expect(result, isA<Map<String, dynamic>>());
expect(result, isEmpty);
});
}
13 changes: 13 additions & 0 deletions test/platform/fake_usercentrics_platform.dart
Original file line number Diff line number Diff line change
Expand Up @@ -399,4 +399,17 @@ class FakeUsercentricsPlatform extends UsercentricsPlatform {
Stream<GppSectionChangePayload> get onGppSectionChange {
return const Stream.empty();
}

Map<String, dynamic>? dpsMetadataAnswer;
var dpsMetadataCount = 0;
String? dpsMetadataTemplateIdArgument;

@override
Future<Map<String, dynamic>?> getDpsMetadata({
required String templateId,
}) {
dpsMetadataCount++;
dpsMetadataTemplateIdArgument = templateId;
return Future.value(dpsMetadataAnswer);
}
}
Loading