Test Utf8FromUtf16 (#118647)

diff --git a/dev/integration_tests/windows_startup_test/lib/main.dart b/dev/integration_tests/windows_startup_test/lib/main.dart
index 1ebd1e4..d83a911 100644
--- a/dev/integration_tests/windows_startup_test/lib/main.dart
+++ b/dev/integration_tests/windows_startup_test/lib/main.dart
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import 'dart:async';
+import 'dart:typed_data';
 import 'dart:ui' as ui;
 
 import 'package:flutter_driver/driver_extension.dart';
@@ -44,6 +45,18 @@
       return (app == system)
         ? 'success'
         : 'error: app dark mode ($app) does not match system dark mode ($system)';
+    } else if (message == 'verifyStringConversion') {
+      // Use a test string that contains code points that fit in both 8 and 16 bits.
+      // The code points are passed a list of integers through the method channel,
+      // which will use the UTF16 to UTF8 utility function to convert them to a
+      // std::string, which should equate to the original expected string.
+      // TODO(schectman): Remove trailing null from returned string
+      const String expected = 'ABCℵ\x00';
+      final Int32List codePoints = Int32List.fromList(expected.codeUnits);
+      final String converted = await testStringConversion(codePoints);
+      return (converted == expected)
+        ? 'success'
+        : 'error: conversion of UTF16 string to UTF8 failed, expected "${expected.codeUnits}" but got "${converted.codeUnits}"';
     }
 
     throw 'Unrecognized message: $message';
diff --git a/dev/integration_tests/windows_startup_test/lib/windows.dart b/dev/integration_tests/windows_startup_test/lib/windows.dart
index 6773180..d9ab32e 100644
--- a/dev/integration_tests/windows_startup_test/lib/windows.dart
+++ b/dev/integration_tests/windows_startup_test/lib/windows.dart
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'dart:typed_data';
+
 import 'package:flutter/services.dart';
 
 const MethodChannel _kMethodChannel =
@@ -36,3 +38,13 @@
 
   return enabled;
 }
+
+/// Test conversion of a UTF16 string to UTF8 using the app template utils.
+Future<String> testStringConversion(Int32List twoByteCodes) async {
+  final String? converted = await _kMethodChannel.invokeMethod<String?>('convertString', twoByteCodes);
+  if (converted == null) {
+    throw 'Method channel unavailable.';
+  }
+
+  return converted;
+}
diff --git a/dev/integration_tests/windows_startup_test/test_driver/main_test.dart b/dev/integration_tests/windows_startup_test/test_driver/main_test.dart
index a002fb6..b34e950 100644
--- a/dev/integration_tests/windows_startup_test/test_driver/main_test.dart
+++ b/dev/integration_tests/windows_startup_test/test_driver/main_test.dart
@@ -23,4 +23,13 @@
 
     await driver.close();
   }, timeout: Timeout.none);
+
+  test('Windows app template can convert string from UTF16 to UTF8', () async {
+    final FlutterDriver driver = await FlutterDriver.connect(printCommunication: true);
+    final String result = await driver.requestData('verifyStringConversion');
+
+    expect(result, equals('success'));
+
+    await driver.close();
+  }, timeout: Timeout.none);
 }
diff --git a/dev/integration_tests/windows_startup_test/windows/runner/flutter_window.cpp b/dev/integration_tests/windows_startup_test/windows/runner/flutter_window.cpp
index a370a27..36023a5 100644
--- a/dev/integration_tests/windows_startup_test/windows/runner/flutter_window.cpp
+++ b/dev/integration_tests/windows_startup_test/windows/runner/flutter_window.cpp
@@ -12,6 +12,7 @@
 #include <flutter/standard_method_codec.h>
 
 #include "flutter/generated_plugin_registrant.h"
+#include "utils.h"
 
 /// Window attribute that enables dark mode window decorations.
 ///
@@ -106,6 +107,15 @@
         } else {
           result->Error("error", "Received status " + status);
         }
+      } else if (method == "convertString") {
+        const flutter::EncodableValue* argument = call.arguments();
+        const std::vector<int32_t> code_points = std::get<std::vector<int32_t>>(*argument);
+        std::vector<wchar_t> wide_str;
+        for (int32_t code_point : code_points) {
+          wide_str.push_back((wchar_t)(code_point));
+        }
+        const std::string string = Utf8FromUtf16(wide_str.data());
+        result->Success(string);
       } else {
         result->NotImplemented();
       }