Skip to content

Commit

Permalink
⚗adding more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
codeimpossible committed Aug 19, 2021
1 parent d049075 commit 6e7bd08
Show file tree
Hide file tree
Showing 19 changed files with 622 additions and 28 deletions.
68 changes: 68 additions & 0 deletions src/Chonks/ChunkDataSegment.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;

namespace Chonks {
public class ChunkDataSegment {
private readonly Dictionary<string, object> _container = new Dictionary<string, object>();
public ChunkDataSegment() { }
public ChunkDataSegment(string json) {
_container = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
}

public string ToJson() {
return JsonConvert.SerializeObject(_container);
}

public Type CheckType(string key) => ContainsKey(key) ? _container[key].GetType() : null;

public bool ContainsKey(string key) => _container.ContainsKey(key);

public bool TryAdd(string key, object value) => _container.TryAdd(key, value);

public bool TryGetInt(string key, out int integer) {
integer = -1;
if (_container.TryGetValue(key, out var value)) {
integer = Convert.ToInt32(value);
return true;
}
return false;
}

public T Get<T>(string key) {
if (!ContainsKey(key)) {
throw new KeyNotFoundException($"The key {key} was not found in the collection.");
}

object box;
T check = default;

// int is a difficult conversion since the default
// for newtonsoft.json is Int64
if (check is int) {
box = Convert.ToInt32(_container[key]);
return (T)box;
}

return (T)_container[key];
}

public bool TryGetBool(string key, out bool boolean) {
boolean = false;
if (_container.TryGetValue(key, out var value)) {
boolean = (bool)value;
return true;
}
return false;
}

public bool TryGetString(string key, out string stringValue) {
stringValue = null;
if (_container.TryGetValue(key, out var value)) {
stringValue = value.ToString();
return true;
}
return false;
}
}
}
102 changes: 98 additions & 4 deletions src/Chonks/Depots/FileSaveDepot.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

Expand All @@ -7,6 +8,27 @@ public class FileSaveDepot : ISaveDepot {
private static readonly SaveContainer[] _emptySaves = new SaveContainer[0];
private string _workingDirectoryPath;

private const string CHUNK_START_MARKER = "";
private const string CHUNK_END_MARKER = "===";
private const string CHUNK_META_END_MARKER = "---";
private const string CHUNK_META_NAME = "name:";
private const string CHUNK_META_ID = "uid:";

private List<Func<string, SaveChunk, SaveChunk>> _metaDataOperators = new List<Func<string, SaveChunk, SaveChunk>>() {
(line, chunk) => {
if (line.StartsWith(CHUNK_META_ID)) {
chunk.Id = new Guid(line.Replace(CHUNK_META_ID, "").Trim());
}
return chunk;
},
(line, chunk) => {
if (line.StartsWith(CHUNK_META_NAME)) {
chunk.Name = line.Replace(CHUNK_META_NAME, "").Trim();
}
return chunk;
}
};

public FileSaveDepot(string workingDirectoryPath) {
_workingDirectoryPath = workingDirectoryPath;
}
Expand All @@ -24,12 +46,84 @@ public class FileSaveDepot : ISaveDepot {
return _emptySaves;
}

public bool TryLoadSave(string name, out SaveChunk[] chunks) {
throw new NotImplementedException();
public bool TryLoadSave(string name, out SaveChunk[] chunks, out Exception ex) {
EnsureWorkingDirectory();
ex = null;
chunks = new SaveChunk[0];
try {
var readChunks = new List<SaveChunk>();
using (var fs = new FileStream(Path.Combine(_workingDirectoryPath, $"{name}.sav"), FileMode.Open, FileAccess.Read)) {
using (var reader = new StreamReader(fs)) {
string? line = "";
var chunk = new SaveChunk();
var inChunk = false;
var inMetaData = false;
while (line != null) {
line = reader.ReadLine();
if (!inChunk && line == CHUNK_START_MARKER) {
chunk = new SaveChunk();
inChunk = true;
inMetaData = true;
continue;
}

if (inChunk && line == CHUNK_META_END_MARKER) {
inMetaData = false;
continue;
}

if (line == CHUNK_END_MARKER) {
readChunks.Add(chunk);
inChunk = false;
continue;
}

if (inChunk) {
if (inMetaData) {
foreach (var op in _metaDataOperators) {
chunk = op(line, chunk);
}
} else {
var key = line.Split(':')[0] + ":";
var json = line.Replace(key, "").Trim();
chunk.Data.Add(key.Replace(":", ""), json);
}
continue;
}
}
}
}
chunks = readChunks.ToArray();
return true;
} catch (Exception e) {
ex = e;
return false;
}
}

public bool TryWriteSave(string name, SaveChunk[] chunks) {
throw new NotImplementedException();
public bool TryWriteSave(string name, SaveChunk[] chunks, out Exception ex) {
EnsureWorkingDirectory();
ex = null;
try {
using (var fs = new FileStream(Path.Combine(_workingDirectoryPath, $"{name}.sav"), FileMode.OpenOrCreate, FileAccess.Write)) {
using (var writer = new StreamWriter(fs)) {
foreach (var chunk in chunks) {
writer.WriteLine(CHUNK_START_MARKER);
writer.WriteLine($"uid: {chunk.Id}");
writer.WriteLine($"name: {chunk.Name}");
writer.WriteLine(CHUNK_META_END_MARKER);
foreach (var segment in chunk.Data) {
writer.WriteLine($"{segment.Key}: {segment.Value}");
}
writer.WriteLine(CHUNK_END_MARKER);
}
}
}
return true;
} catch (Exception e) {
ex = e;
return false;
}
}

internal void Cleanup() {
Expand Down
10 changes: 5 additions & 5 deletions src/Chonks/Depots/InMemorySaveDepot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ public class InMemorySaveDepot : ISaveDepot {
private readonly List<SaveContainer> _containers = new List<SaveContainer>();
private readonly Dictionary<string, SaveChunk[]> _chunks = new Dictionary<string, SaveChunk[]>();

public SaveContainer[] ListSaves() {
return _containers.ToArray();
}
public SaveContainer[] ListSaves() => _containers.ToArray();

public bool TryLoadSave(string name, out SaveChunk[] chunks) {
public bool TryLoadSave(string name, out SaveChunk[] chunks, out Exception ex) {
ex = null;
chunks = new SaveChunk[0];
if (_chunks.TryGetValue(name, out chunks)) {
return true;
}
return false;
}

public bool TryWriteSave(string name, SaveChunk[] chunks) {
public bool TryWriteSave(string name, SaveChunk[] chunks, out Exception ex) {
ex = null;
if (_chunks.TryAdd(name, chunks)) {
_containers.Add(new SaveContainer() { Name = name, CreatedAt = DateTime.UtcNow, LastUpdatedAt = DateTime.UtcNow });
return true;
Expand Down
8 changes: 5 additions & 3 deletions src/Chonks/ISaveDepot.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
namespace Chonks {
using System;

namespace Chonks {
public interface ISaveDepot {
SaveContainer[] ListSaves();
bool TryLoadSave(string name, out SaveChunk[] chunks);
bool TryWriteSave(string name, SaveChunk[] chunks);
bool TryLoadSave(string name, out SaveChunk[] chunks, out Exception ex);
bool TryWriteSave(string name, SaveChunk[] chunks, out Exception ex);
}
}
2 changes: 1 addition & 1 deletion src/Chonks/ISaveStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ public class SaveState {
public interface ISaveStore {
string GetStoreIdentifier();
List<SaveState> CreateSaveStates();
void ProcessStates(params SaveState[] states);
void ProcessChunkData(string chunkName, ChunkDataSegment data);
}
}
11 changes: 4 additions & 7 deletions src/Chonks/SaveChunk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,13 @@
namespace Chonks {

[Serializable]
public struct SaveChunk {
private readonly static JsonSerializer _serializer = JsonSerializer.Create();
public Guid Id { get; set; }
public class SaveChunk {
public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; }
public Dictionary<string, string> Data { get; set; }
public Dictionary<string, string> Data { get; set; } = new Dictionary<string, string>();

public SaveChunk(string name) {
public SaveChunk(string name = "") {
Name = name;
Id = Guid.NewGuid();
Data = new Dictionary<string, string>();
}

public override int GetHashCode() {
Expand Down
12 changes: 6 additions & 6 deletions src/Chonks/SaveManagement/DefaultSaveManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ public class DefaultSaveManager : ISaveManager {
}

public void LoadSnapshot(SaveContainer container) {
if (_depot.TryLoadSave(container.Name, out var chunks)) {
if (_depot.TryLoadSave(container.Name, out var chunks, out _)) {
_snapshot = chunks;
ProcessSnapshotUpdate();
}
}

public void ApplySnapshot(SaveContainer container) {
if (_snapshot == null) return;
if (_depot.TryWriteSave(container.Name, _snapshot)) {
if (_depot.TryWriteSave(container.Name, _snapshot, out _)) {
ProcessSnapshotUpdate();
}
}
Expand All @@ -37,8 +37,10 @@ public class DefaultSaveManager : ISaveManager {
SaveChunk chunk;
if (!chunks.TryGetValue(state.ChunkName, out chunk)) {
chunk = new SaveChunk(state.ChunkName);
chunks.Add(chunk.Name, chunk);
}
chunk.AddToChunk(id, state.Data);
chunks[chunk.Name] = chunk;
}
}

Expand All @@ -50,16 +52,14 @@ public class DefaultSaveManager : ISaveManager {
}

private void ProcessSnapshotUpdate() {
var states = new List<SaveState>();
foreach (var store in _controller.GetSaveStores()) {
states.Clear();
var id = store.GetStoreIdentifier();
foreach (var chunk in _snapshot) {
if (chunk.Data.TryGetValue(id, out var json)) {
states.Add(new SaveState() { ChunkName = chunk.Name, Data = json });
var segment = new ChunkDataSegment(json);
store.ProcessChunkData(chunk.Name, segment);
}
}
store.ProcessStates(states.ToArray());
}

foreach (var interpreter in _controller.GetSaveInterpreters()) {
Expand Down
1 change: 1 addition & 0 deletions tests/Chonks.Tests/Chonks.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
<PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Loading

0 comments on commit 6e7bd08

Please sign in to comment.