From 26812ffe9c07a4176f8366e2150a4241abdd9a70 Mon Sep 17 00:00:00 2001 From: Aleksey Kulikov Date: Wed, 20 Oct 2021 11:29:41 +0300 Subject: [PATCH] test(config): add more test cases --- lib/src/bindings/config.dart | 84 ++++---------------------- lib/src/config.dart | 27 ++++----- test/config_test.dart | 111 ++++++++++++++++++++++++++++++++--- 3 files changed, 128 insertions(+), 94 deletions(-) diff --git a/lib/src/bindings/config.dart b/lib/src/bindings/config.dart index cd577b0..f4eefde 100644 --- a/lib/src/bindings/config.dart +++ b/lib/src/bindings/config.dart @@ -1,43 +1,20 @@ +// coverage:ignore-file + import 'dart:ffi'; import 'package:ffi/ffi.dart'; import '../error.dart'; import 'libgit2_bindings.dart'; import '../util.dart'; -/// Allocate a new configuration object -/// -/// This object is empty, so you have to add a file to it before you can do -/// anything with it. -/// -/// Throws a [LibGit2Error] if error occured. -Pointer newConfig() { - final out = calloc>(); - final error = libgit2.git_config_new(out); - - if (error < 0) { - calloc.free(out); - throw LibGit2Error(libgit2.git_error_last()); - } else { - return out.value; - } -} - /// Create a new config instance containing a single on-disk file -/// -/// Throws a [LibGit2Error] if error occured. Pointer open(String path) { final out = calloc>(); final pathC = path.toNativeUtf8().cast(); - final error = libgit2.git_config_open_ondisk(out, pathC); + libgit2.git_config_open_ondisk(out, pathC); calloc.free(pathC); - if (error < 0) { - calloc.free(out); - throw LibGit2Error(libgit2.git_error_last()); - } else { - return out.value; - } + return out.value; } /// Open the global, XDG and system configuration files @@ -71,14 +48,14 @@ Pointer openDefault() { /// This method will not guess the path to the xdg compatible config file /// (`.config/git/config`). /// -/// Throws an error if file has not been found. +/// Throws a [LibGit2Error] if error occured. String findGlobal() { final out = calloc(sizeOf()); final error = libgit2.git_config_find_global(out); - if (error != 0) { + if (error < 0) { calloc.free(out); - throw Error(); + throw LibGit2Error(libgit2.git_error_last()); } else { final result = out.ref.ptr.cast().toDartString(); calloc.free(out); @@ -130,18 +107,10 @@ String findXdg() { /// Create a snapshot of the current state of a configuration, which allows you to look /// into a consistent view of the configuration for looking up complex values /// (e.g. a remote, submodule). -/// -/// Throws a [LibGit2Error] if error occured. Pointer snapshot(Pointer config) { final out = calloc>(); - final error = libgit2.git_config_snapshot(out, config); - - if (error < 0) { - calloc.free(out); - throw LibGit2Error(libgit2.git_error_last()); - } else { - return out.value; - } + libgit2.git_config_snapshot(out, config); + return out.value; } /// Get the config entry of a config variable. @@ -167,8 +136,6 @@ Pointer getEntry({ /// Set the value of a boolean config variable in the config file with the /// highest level (usually the local one). -/// -/// Throws a [LibGit2Error] if error occured. void setBool({ required Pointer configPointer, required String variable, @@ -176,38 +143,24 @@ void setBool({ }) { final name = variable.toNativeUtf8().cast(); final valueC = value ? 1 : 0; - final error = libgit2.git_config_set_bool(configPointer, name, valueC); - + libgit2.git_config_set_bool(configPointer, name, valueC); calloc.free(name); - - if (error < 0) { - throw LibGit2Error(libgit2.git_error_last()); - } } /// Set the value of an integer config variable in the config file with the /// highest level (usually the local one). -/// -/// Throws a [LibGit2Error] if error occured. void setInt({ required Pointer configPointer, required String variable, required int value, }) { final name = variable.toNativeUtf8().cast(); - final error = libgit2.git_config_set_int64(configPointer, name, value); - + libgit2.git_config_set_int64(configPointer, name, value); calloc.free(name); - - if (error < 0) { - throw LibGit2Error(libgit2.git_error_last()); - } } /// Set the value of a string config variable in the config file with the /// highest level (usually the local one). -/// -/// Throws a [LibGit2Error] if error occured. void setString({ required Pointer configPointer, required String variable, @@ -215,14 +168,9 @@ void setString({ }) { final name = variable.toNativeUtf8().cast(); final valueC = value.toNativeUtf8().cast(); - final error = libgit2.git_config_set_string(configPointer, name, valueC); - + libgit2.git_config_set_string(configPointer, name, valueC); calloc.free(name); calloc.free(valueC); - - if (error < 0) { - throw LibGit2Error(libgit2.git_error_last()); - } } /// Iterate over all the config variables. @@ -330,13 +278,5 @@ void deleteMultivar({ calloc.free(regexpC); } -/// Free a config iterator. -void iteratorFree(Pointer iter) => - libgit2.git_config_iterator_free(iter); - -/// Free a config entry. -void entryFree(Pointer entry) => - libgit2.git_config_entry_free(entry); - /// Free the configuration and its associated memory and files. void free(Pointer cfg) => libgit2.git_config_free(cfg); diff --git a/lib/src/config.dart b/lib/src/config.dart index 29024b5..781f459 100644 --- a/lib/src/config.dart +++ b/lib/src/config.dart @@ -11,7 +11,7 @@ class Config with IterableMixin { /// Initializes a new instance of [Config] class from provided /// pointer to config object in memory. /// - /// Should be freed with `free()` to release allocated memory. + /// Should be freed to release allocated memory. Config(this._configPointer); /// Initializes a new instance of [Config] class from provided [path]. @@ -21,7 +21,9 @@ class Config with IterableMixin { /// [path] should point to single on-disk file; it's expected to be a native /// Git config file following the default Git config syntax (see man git-config). /// - /// Should be freed with `free()` to release allocated memory. + /// Should be freed to release allocated memory. + /// + /// Throws an [Exception] if file not found at provided path. Config.open([String? path]) { libgit2.git_libgit2_init(); @@ -40,42 +42,39 @@ class Config with IterableMixin { /// /// Opens the system configuration file. /// - /// Should be freed with `free()` to release allocated memory. + /// Should be freed to release allocated memory. /// /// Throws a [LibGit2Error] if error occured. Config.system() { libgit2.git_libgit2_init(); - final systemPath = bindings.findSystem(); - _configPointer = bindings.open(systemPath); + _configPointer = bindings.open(bindings.findSystem()); } /// Initializes a new instance of [Config] class. /// /// Opens the global configuration file. /// - /// Should be freed with `free()` to release allocated memory. + /// Should be freed to release allocated memory. /// - /// Throws an error if file has not been found. + /// Throws a [LibGit2Error] if error occured. Config.global() { libgit2.git_libgit2_init(); - final globalPath = bindings.findGlobal(); - _configPointer = bindings.open(globalPath); + _configPointer = bindings.open(bindings.findGlobal()); } /// Initializes a new instance of [Config] class. /// /// Opens the global XDG configuration file. /// - /// Should be freed with `free()` to release allocated memory. + /// Should be freed to release allocated memory. /// /// Throws a [LibGit2Error] if error occured. Config.xdg() { libgit2.git_libgit2_init(); - final xdgPath = bindings.findXdg(); - _configPointer = bindings.open(xdgPath); + _configPointer = bindings.open(bindings.findXdg()); } /// Pointer to memory address for allocated config object. @@ -86,8 +85,6 @@ class Config with IterableMixin { /// Create a snapshot of the current state of a configuration, which allows you to look /// into a consistent view of the configuration for looking up complex values /// (e.g. a remote, submodule). - /// - /// Throws a [LibGit2Error] if error occured. Config get snapshot => Config(bindings.snapshot(_configPointer)); /// Returns the [ConfigEntry] of a [variable]. @@ -206,7 +203,7 @@ class ConfigEntry { } /// Releases memory allocated for config entry object. - void free() => bindings.entryFree(_configEntryPointer); + void free() => calloc.free(_configEntryPointer); @override String toString() { diff --git a/test/config_test.dart b/test/config_test.dart index e4a23b7..b73536d 100644 --- a/test/config_test.dart +++ b/test/config_test.dart @@ -15,6 +15,14 @@ void main() { \turl = someurl '''; + const expectedEntries = [ + 'core.repositoryformatversion', + 'core.bare', + 'core.gitproxy', + 'core.gitproxy', + 'remote.origin.url', + ]; + late Config config; setUp(() { @@ -28,16 +36,80 @@ void main() { }); group('Config', () { - test('opens file successfully with provided path', () { + test('successfully opens file with provided path', () { expect(config, isA()); }); + test( + 'opens the global, XDG and system configuration files (if they are present) ' + 'if no path provided', () { + try { + final config = Config.open(); + expect(config, isA()); + config.free(); + } catch (e) { + expect(() => Config.open(), throwsA(isA())); + } + }); + + test('throws when trying to open non existing file', () { + expect( + () => Config.open('not.there'), + throwsA( + isA().having( + (e) => e.toString(), + 'error', + "Exception: File not found", + ), + ), + ); + }); + + test('successfully opens system file or throws is there is none', () { + try { + final config = Config.system(); + expect(config, isA()); + config.free(); + } catch (e) { + expect(() => Config.system(), throwsA(isA())); + } + }); + + test('successfully opens global file or throws is there is none', () { + try { + final config = Config.global(); + expect(config, isA()); + config.free(); + } catch (e) { + expect(() => Config.global(), throwsA(isA())); + } + }); + + test('successfully opens xdg file or throws is there is none', () { + try { + final config = Config.xdg(); + expect(config, isA()); + config.free(); + } catch (e) { + expect(() => Config.xdg(), throwsA(isA())); + } + }); + + test('returns config snapshot', () { + final snapshot = config.snapshot; + expect(snapshot, isA()); + snapshot.free(); + }); + test('returns config entries and their values', () { - expect(config.length, 5); - expect(config.last.name, 'remote.origin.url'); - expect(config.last.value, 'someurl'); - expect(config.last.includeDepth, 0); - expect(config.last.level, GitConfigLevel.local); + var i = 0; + for (final entry in config) { + expect(entry.name, expectedEntries[i]); + expect(entry.includeDepth, 0); + expect(entry.level, GitConfigLevel.local); + entry.free(); + i++; + } }); group('get value', () { @@ -48,7 +120,13 @@ void main() { test('throws when variable isn\'t found', () { expect( () => config['not.there'], - throwsA(isA()), + throwsA( + isA().having( + (e) => e.toString(), + 'error', + "config value 'not.there' was not found", + ), + ), ); }); }); @@ -68,6 +146,19 @@ void main() { config['remote.origin.url'] = 'updated'; expect(config['remote.origin.url'].value, 'updated'); }); + + test('throws when trying to set invalid value', () { + expect( + () => config['remote.origin.url'] = 0.1, + throwsA( + isA().having( + (e) => e.toString(), + 'error', + 'Invalid argument: "0.1 must be either bool, int or String"', + ), + ), + ); + }); }); group('delete', () { @@ -176,5 +267,11 @@ void main() { expect(config.multivar(variable: 'core.gitproxy'), []); }); }); + + test('returns string representation of ConfigEntry object', () { + final entry = config.first; + expect(entry.toString(), contains('ConfigEntry{')); + entry.free(); + }); }); }