| // Copyright 2014 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:typed_data'; |
| |
| import 'package:file/memory.dart'; |
| import 'package:file_testing/file_testing.dart'; |
| import 'package:flutter_tools/src/base/file_system.dart'; |
| import 'package:flutter_tools/src/base/logger.dart'; |
| import 'package:flutter_tools/src/base/template.dart'; |
| import 'package:flutter_tools/src/cache.dart'; |
| import 'package:flutter_tools/src/globals.dart' as globals; |
| import 'package:flutter_tools/src/template.dart'; |
| import '../src/common.dart'; |
| import '../src/context.dart'; |
| |
| void main() { |
| testWithoutContext('Template constructor throws ToolExit when source directory is missing', () { |
| final FileExceptionHandler handler = FileExceptionHandler(); |
| final MemoryFileSystem fileSystem = MemoryFileSystem.test(opHandle: handler.opHandle); |
| |
| expect(() => Template( |
| fileSystem.directory('doesNotExist'), |
| fileSystem.currentDirectory, |
| fileSystem: fileSystem, |
| logger: BufferLogger.test(), |
| templateRenderer: FakeTemplateRenderer(), |
| ), throwsToolExit()); |
| }); |
| |
| testWithoutContext('Template.render throws ToolExit when FileSystem exception is raised', () { |
| final FileExceptionHandler handler = FileExceptionHandler(); |
| final MemoryFileSystem fileSystem = MemoryFileSystem.test(opHandle: handler.opHandle); |
| final Template template = Template( |
| fileSystem.directory('examples')..createSync(recursive: true), |
| fileSystem.currentDirectory, |
| fileSystem: fileSystem, |
| logger: BufferLogger.test(), |
| templateRenderer: FakeTemplateRenderer(), |
| ); |
| final Directory directory = fileSystem.directory('foo'); |
| handler.addError(directory, FileSystemOp.create, const FileSystemException()); |
| |
| expect(() => template.render(directory, <String, Object>{}), |
| throwsToolExit()); |
| }); |
| |
| group('template image directory', () { |
| final Map<Type, Generator> overrides = <Type, Generator>{ |
| FileSystem: () => MemoryFileSystem.test(), |
| ProcessManager: () => FakeProcessManager.any(), |
| }; |
| const TemplatePathProvider templatePathProvider = TemplatePathProvider(); |
| |
| testUsingContext('templatePathProvider.imageDirectory returns parent template directory if passed null name', () async { |
| final String packageConfigPath = globals.fs.path.join( |
| Cache.flutterRoot!, |
| 'packages', |
| 'flutter_tools', |
| '.dart_tool', |
| 'package_config.json', |
| ); |
| |
| globals.fs.file(packageConfigPath) |
| ..createSync(recursive: true) |
| ..writeAsStringSync(''' |
| { |
| "configVersion": 2, |
| "packages": [ |
| { |
| "name": "flutter_template_images", |
| "rootUri": "/flutter_template_images", |
| "packageUri": "lib/", |
| "languageVersion": "2.12" |
| } |
| ] |
| } |
| '''); |
| expect( |
| (await templatePathProvider.imageDirectory(null, globals.fs, globals.logger)).path, |
| globals.fs.path.absolute( |
| 'flutter_template_images', |
| 'templates', |
| ), |
| ); |
| }, overrides: overrides); |
| |
| testUsingContext('templatePathProvider.imageDirectory returns the directory containing the `name` template directory', () async { |
| final String packageConfigPath = globals.fs.path.join( |
| Cache.flutterRoot!, |
| 'packages', |
| 'flutter_tools', |
| '.dart_tool', |
| 'package_config.json', |
| ); |
| globals.fs.file(packageConfigPath) |
| ..createSync(recursive: true) |
| ..writeAsStringSync(''' |
| { |
| "configVersion": 2, |
| "packages": [ |
| { |
| "name": "flutter_template_images", |
| "rootUri": "/flutter_template_images", |
| "packageUri": "lib/", |
| "languageVersion": "2.12" |
| } |
| ] |
| } |
| '''); |
| expect( |
| (await templatePathProvider.imageDirectory('app_shared', globals.fs, globals.logger)).path, |
| globals.fs.path.absolute( |
| 'flutter_template_images', |
| 'templates', |
| 'app_shared', |
| ), |
| ); |
| }, overrides: overrides); |
| }); |
| |
| group('renders template', () { |
| late Directory destination; |
| const String imageName = 'some_image.png'; |
| late File sourceImage; |
| late BufferLogger logger; |
| late Template template; |
| |
| setUp(() { |
| final MemoryFileSystem fileSystem = MemoryFileSystem.test(); |
| final Directory templateDir = fileSystem.directory('templates'); |
| final Directory imageSourceDir = fileSystem.directory('template_images'); |
| destination = fileSystem.directory('target'); |
| templateDir.childFile('$imageName.img.tmpl').createSync(recursive: true); |
| sourceImage = imageSourceDir.childFile(imageName); |
| sourceImage.createSync(recursive: true); |
| sourceImage.writeAsStringSync("Ceci n'est pas une pipe"); |
| |
| logger = BufferLogger.test(); |
| template = Template( |
| templateDir, |
| imageSourceDir, |
| fileSystem: fileSystem, |
| logger: logger, |
| templateRenderer: FakeTemplateRenderer(), |
| ); |
| }); |
| |
| testWithoutContext('overwrites .img.tmpl files with files from the image source', () { |
| expect(template.render(destination, <String, Object>{}), 1); |
| |
| final File destinationImage = destination.childFile(imageName); |
| final Uint8List sourceImageBytes = sourceImage.readAsBytesSync(); |
| expect(destinationImage, exists); |
| expect(destinationImage.readAsBytesSync(), equals(sourceImageBytes)); |
| |
| expect(logger.errorText, isEmpty); |
| expect(logger.statusText, contains('${destinationImage.path} (created)')); |
| logger.clear(); |
| |
| // Run it again to overwrite (returns 1 file updated). |
| expect(template.render(destination, <String, Object>{}), 1); |
| |
| expect(destinationImage.readAsBytesSync(), equals(sourceImageBytes)); |
| expect(logger.errorText, isEmpty); |
| expect(logger.statusText, contains('${destinationImage.path} (overwritten)')); |
| }); |
| |
| testWithoutContext('does not overwrite .img.tmpl files with files from the image source', () { |
| expect(template.render(destination, <String, Object>{}), 1); |
| |
| final File destinationImage = destination.childFile(imageName); |
| expect(destinationImage, exists); |
| |
| expect(logger.errorText, isEmpty); |
| expect(logger.statusText, contains('${destinationImage.path} (created)')); |
| logger.clear(); |
| |
| // Run it again, do not overwrite (returns 0 files updated). |
| expect(template.render(destination, <String, Object>{}, overwriteExisting: false), 0); |
| |
| expect(destinationImage, exists); |
| expect(logger.errorText, isEmpty); |
| expect(logger.statusText, isEmpty); |
| }); |
| |
| testWithoutContext('can suppress file printing', () { |
| template.render(destination, <String, Object>{}, printStatusWhenWriting: false); |
| |
| final File destinationImage = destination.childFile(imageName); |
| expect(destinationImage, exists); |
| |
| expect(logger.errorText, isEmpty); |
| expect(logger.statusText, isEmpty); |
| }); |
| }); |
| |
| testWithoutContext('escapeYamlString', () { |
| expect(escapeYamlString(''), r'""'); |
| expect(escapeYamlString('\x00\n\r\t\b'), r'"\0\n\r\t\x08"'); |
| expect(escapeYamlString('test'), r'"test"'); |
| expect(escapeYamlString('test\n test'), r'"test\n test"'); |
| expect(escapeYamlString('\x00\x01\x02\x0c\x19\xab'), r'"\0\x01\x02\x0c\x19«"'); |
| expect(escapeYamlString('"'), r'"\""'); |
| expect(escapeYamlString(r'\'), r'"\\"'); |
| expect(escapeYamlString('[user branch]'), r'"[user branch]"'); |
| expect(escapeYamlString('main'), r'"main"'); |
| expect(escapeYamlString('TEST_BRANCH'), r'"TEST_BRANCH"'); |
| expect(escapeYamlString(' '), r'" "'); |
| expect(escapeYamlString(' \n '), r'" \n "'); |
| expect(escapeYamlString('""'), r'"\"\""'); |
| expect(escapeYamlString('"\x01\u{0263A}\u{1F642}'), r'"\"\x01☺🙂"'); |
| }); |
| } |
| |
| class FakeTemplateRenderer extends TemplateRenderer { |
| @override |
| String renderString(String template, dynamic context, {bool htmlEscapeValues = false}) { |
| return ''; |
| } |
| } |