├── .gitignore ├── .hgignore ├── Examples ├── Client │ ├── AuthenticationExamples.cs │ └── CommunicationExamples.cs ├── Examples.csproj └── Values │ ├── HaystackDictionaryExamples.cs │ └── HaystackGridExamples.cs ├── GitVersion.yml ├── LICENSE.txt ├── ProjectHaystack.BackCompat ├── Client │ ├── HttpAsyncClient.cs │ ├── IHAsyncClient.cs │ └── IHClient.cs ├── Mapping │ └── HaystackValueMapper.cs ├── ProjectHaystack - Backup (1).BackCompat.csproj ├── ProjectHaystack - Backup.BackCompat.csproj ├── ProjectHaystack.BackCompat.csproj ├── ProjectHaystack.BackCompat.nuspec └── Values │ ├── CHaystackTZDB.cs │ ├── HBin.cs │ ├── HBool.cs │ ├── HCol.cs │ ├── HCoord.cs │ ├── HDate.cs │ ├── HDateTime.cs │ ├── HDateTimeRange.cs │ ├── HDef.cs │ ├── HDict.cs │ ├── HDictBuilder.cs │ ├── HGrid.cs │ ├── HGridBuilder.cs │ ├── HHisItem.cs │ ├── HList.cs │ ├── HMarker.cs │ ├── HNA.cs │ ├── HNum.cs │ ├── HRef.cs │ ├── HRemove.cs │ ├── HRow.cs │ ├── HStr.cs │ ├── HTime.cs │ ├── HTimeZone.cs │ ├── HUri.cs │ ├── HVal.cs │ ├── HXStr.cs │ └── IHProj.cs ├── ProjectHaystack.sln ├── ProjectHaystack ├── Auth │ ├── AutodetectAuthenticator.cs │ ├── BasicAuthenticator.cs │ ├── IAuthenticator.cs │ ├── NonHaystackBasicAuthenticator.cs │ ├── ScramAuthenticator.cs │ └── Util │ │ ├── Base64.cs │ │ └── Pbkdf2.cs ├── Builders │ └── HaystackDateTimeRangeBuilder.cs ├── Client │ ├── HaystackClient.cs │ └── IHaystackClient.cs ├── Constants │ └── HaystackTimeZoneDatabase.cs ├── Exceptions │ ├── HaystackAuthException.cs │ ├── HaystackException.cs │ └── HaystackUnknownNameException.cs ├── Extensions │ ├── HaystackDictionaryExtensions.cs │ ├── IHaystackClientExtensions.cs │ └── UriExtensions.cs ├── OSS_TimeZoneConverter.txt ├── Program.cs ├── ProjectHaystack.csproj ├── ProjectHaystack.nuspec ├── Properties │ └── launchSettings.json ├── Validation │ └── HaystackValidator.cs ├── Values │ ├── HaystackBinary.cs │ ├── HaystackBoolean.cs │ ├── HaystackCaretSymbol.cs │ ├── HaystackColumn.cs │ ├── HaystackCoordinate.cs │ ├── HaystackDate.cs │ ├── HaystackDateTime.cs │ ├── HaystackDateTimeRange.cs │ ├── HaystackDefinition.cs │ ├── HaystackDictionary.cs │ ├── HaystackGrid.cs │ ├── HaystackHistoryItem.cs │ ├── HaystackList.cs │ ├── HaystackMarker.cs │ ├── HaystackNotAvailable.cs │ ├── HaystackNumber.cs │ ├── HaystackReference.cs │ ├── HaystackRemove.cs │ ├── HaystackRow.cs │ ├── HaystackString.cs │ ├── HaystackTime.cs │ ├── HaystackTimeZone.cs │ ├── HaystackUri.cs │ ├── HaystackValue.cs │ └── HaystackXString.cs ├── app.config └── io │ ├── HaysonWriter.cs │ ├── HaystackToken.cs │ ├── HaystackTokenizer.cs │ ├── TrioReader.cs │ ├── TrioWriter.cs │ ├── ZincReader.cs │ └── ZincWriter.cs ├── ProjectHaystackTest ├── Auth │ └── Util │ │ ├── Base64Test.cs │ │ └── Pbkdf2Test.cs ├── BackCompat │ ├── HBinTest.cs │ ├── HBoolTest.cs │ ├── HCoordTest.cs │ ├── HDateTest.cs │ ├── HDateTimeRangeTest.cs │ ├── HDateTimeTest.cs │ ├── HDefTest.cs │ ├── HDictTest.cs │ ├── HGridTest.cs │ ├── HHisItemTest.cs │ ├── HListTest.cs │ ├── HMarkerTest.cs │ ├── HNumTest.cs │ ├── HRefTest.cs │ ├── HRowTest.cs │ ├── HStrTest.cs │ ├── HTimeTest.cs │ ├── HTimeZoneTest.cs │ ├── HTzTest.cs │ ├── HUriTest.cs │ ├── HValTest.cs │ ├── HXStrTest.cs │ ├── HaystackTest.cs │ ├── ProjectHaystackTest.csproj │ ├── Util │ │ └── UtilTest.cs │ ├── packages.config │ └── playlistBaseLibTests.playlist ├── Builders │ └── HaystackDateTimeRangeBuilderTests.cs ├── Client │ └── HaystackClientTest.cs ├── Mocks │ └── HttpClientMockBuilder.cs ├── Obsolete │ └── HFilterTest.cs ├── ProjectHaystackTest.csproj ├── Validation │ └── HaystackValidatorTests.cs ├── Values │ ├── HaystackBinaryTests.cs │ ├── HaystackBooleanTests.cs │ ├── HaystackCoordinateTests.cs │ ├── HaystackDateTests.cs │ ├── HaystackDateTimeTests.cs │ ├── HaystackDefinitionTests.cs │ ├── HaystackDictionaryTests.cs │ ├── HaystackGridTests.cs │ ├── HaystackListTests.cs │ ├── HaystackMarkerTests.cs │ ├── HaystackNumberTests.cs │ ├── HaystackReferenceTests.cs │ ├── HaystackRowTests.cs │ ├── HaystackStringTests.cs │ ├── HaystackTimeTests.cs │ ├── HaystackTimeZoneTests.cs │ ├── HaystackUriTests.cs │ └── HaystackXStringTests.cs ├── io │ ├── HZincReaderTests.cs │ ├── HaysonWriterTests.cs │ ├── TokenizerTests.cs │ ├── TrioReaderTests.cs │ ├── TrioWriterTests.cs │ └── ZincWriterTests.cs ├── packages.config └── playlistBaseLibTests.playlist ├── README.md ├── build-system └── unix-pr-validation.yml └── global.json /.hgignore: -------------------------------------------------------------------------------- 1 | # ignore files 2 | 3 | # globs in any directory 4 | syntax: glob 5 | 6 | .DS_Store 7 | Thumbs.db 8 | temp/ 9 | doc/ 10 | staging/ 11 | haystack.jar 12 | 13 | # Visual Studio 14 | .vs/ 15 | bin/ 16 | obj/ 17 | packages/ 18 | *.csproj.user 19 | 20 | # Nuget 21 | *.nupkg 22 | -------------------------------------------------------------------------------- /Examples/Client/AuthenticationExamples.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | using ProjectHaystack.Auth; 5 | using ProjectHaystack.Client; 6 | 7 | namespace ProjectHaystack.Examples.Client 8 | { 9 | /// 10 | /// Examples on how to set up an authenticated connection. 11 | /// If your system does not support any of the known authenticators, 12 | /// you can write your own by implementing IAuthenticator. 13 | /// Please be so kind to share your implementation with the world by adding it to this library. 14 | /// 15 | public class AuthenticationExamples 16 | { 17 | /// 18 | /// Connect using scram authentication. 19 | /// This will set a cookie on the HttpClient. 20 | /// 21 | public async Task ConnectUsingScramAuthentication() 22 | { 23 | var user = "someuser"; 24 | var pass = "somepassword"; 25 | var uri = new Uri("https://someserver/api/"); 26 | var auth = new ScramAuthenticator(user, pass); 27 | // When authentications fails in certain legacy systems, set this value to true. 28 | auth.AddLegacySpaceToProof = true; 29 | var client = new HaystackClient(auth, uri); 30 | await client.OpenAsync(); 31 | } 32 | 33 | /// 34 | /// Connect using basic authentication. 35 | /// This will usually set a cookie on the HttpClient. 36 | /// 37 | public async Task ConnectUsingBasicAuthentication() 38 | { 39 | var user = "someuser"; 40 | var pass = "somepassword"; 41 | var uri = new Uri("https://someserver/api/"); 42 | var auth = new BasicAuthenticator(user, pass); 43 | var client = new HaystackClient(auth, uri); 44 | await client.OpenAsync(); 45 | } 46 | 47 | /// 48 | /// Auto-detect authentication scheme. 49 | /// 50 | public async Task ConnectUsingAutodetectAuthentication() 51 | { 52 | var user = "someuser"; 53 | var pass = "somepassword"; 54 | var uri = new Uri("https://someserver/api/"); 55 | var auth = new AutodetectAuthenticator(user, pass); 56 | var client = new HaystackClient(auth, uri); 57 | await client.OpenAsync(); 58 | } 59 | 60 | /// 61 | /// Provide your own HttpClient to get more control over the connection. 62 | /// 63 | public async Task ConnectUsingSharedHttpClient() 64 | { 65 | var user = "someuser"; 66 | var pass = "somepassword"; 67 | var uri = new Uri("https://someserver/api/"); 68 | var auth = new AutodetectAuthenticator(user, pass); 69 | var httpClientHandler = new HttpClientHandler { UseCookies = false, AllowAutoRedirect = false }; 70 | var httpClient = new HttpClient(httpClientHandler); 71 | var client = new HaystackClient(httpClient, auth, uri); 72 | await client.OpenAsync(); 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /Examples/Client/CommunicationExamples.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Threading.Tasks; 3 | using ProjectHaystack.Client; 4 | 5 | namespace ProjectHaystack.Examples.Client 6 | { 7 | /// 8 | /// Examples on how to communicate with the Haystack server. 9 | /// 10 | public class CommunicationExamples 11 | { 12 | private readonly IHaystackClient _haystackClient; 13 | 14 | public CommunicationExamples(IHaystackClient haystackClient) 15 | { 16 | _haystackClient = haystackClient; 17 | } 18 | 19 | /// 20 | /// Get the about page and read its version. 21 | /// 22 | public async Task About() 23 | { 24 | var about = await _haystackClient.AboutAsync(); 25 | var version = about.GetString("haystackVersion"); 26 | } 27 | 28 | /// 29 | /// Get the ops page and read its capabilities. 30 | /// 31 | public async Task Ops() 32 | { 33 | var ops = await _haystackClient.OpsAsync(); 34 | var capabilities = ops.ToDictionary(row => row.GetString("name"), row => row.GetString("summary")); 35 | } 36 | 37 | /// 38 | /// Do a raw call that will not be parsed. 39 | /// This is useful if you mainly want to use the authentication mechanism, 40 | /// but not the data conversion and do conversion elsewhere. 41 | /// You can use this to get specific data types from the server, like json. 42 | /// 43 | public async Task Raw() 44 | { 45 | string aboutAsJson = await _haystackClient.PostStringAsync("about", string.Empty, "text/zinc", "application/json"); 46 | } 47 | 48 | /// 49 | /// When sending more complex requests, like an Axon query in SkySpark 50 | /// you can build and send a grid with a specific operation. 51 | /// 52 | public async Task GridQuery() 53 | { 54 | var axon = "someaxon"; 55 | var grid = new HaystackGrid() 56 | .AddColumn("expr") 57 | .AddRow(new HaystackString(axon)); 58 | HaystackGrid[] result = await _haystackClient.EvalAllAsync(grid); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /Examples/Examples.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | ProjectHaystack.$(MSBuildProjectName.Replace(" ", "_")) 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Examples/Values/HaystackDictionaryExamples.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using ProjectHaystack.Client; 3 | 4 | namespace ProjectHaystack.Examples.Values 5 | { 6 | 7 | /// 8 | /// Examples on how to use a HaystackDictionary. 9 | /// Note that the values inherit HaystackValue, 10 | /// so they should be cast to the expected type to access their values. 11 | /// The ProjectHaystack namespace contains various convenience extension methods 12 | /// for common operations, like reading a string value. 13 | /// 14 | public class HaystackDictionaryExamples 15 | { 16 | private readonly IHaystackClient _haystackClient; 17 | 18 | public HaystackDictionaryExamples(IHaystackClient haystackClient) 19 | { 20 | _haystackClient = haystackClient; 21 | } 22 | 23 | /// 24 | /// Various ways to get values from the dictionary. 25 | /// 26 | public async Task GetValues() 27 | { 28 | var about = await _haystackClient.AboutAsync(); 29 | 30 | // Getting values using the indexer or Get methods. 31 | var value0 = about["key0"]; 32 | var value1 = about.Get("key1"); 33 | var value2 = about.Get("key2"); 34 | // Accessing any key that does not exist will throw an exception, 35 | // so make sure to check if it exists when you are not sure. 36 | var value3 = about.ContainsKey("key3") ? about.Get("key3") : null; 37 | 38 | // GetString is a convenience method that expects the value 39 | // to be a HaystackString, casts it and gets its value. 40 | var value4 = about.GetString("key4"); 41 | 42 | // All *Unchecked convenience methods will not throw an exception 43 | // when the key does not exist, but will return the default value instead. 44 | var value5 = about.GetStringUnchecked("key5"); 45 | } 46 | 47 | /// 48 | /// Various ways to build up a new dictionary. 49 | /// 50 | public void BuildDictionary() 51 | { 52 | // Build a dictionary and add values as you would a normal Dictionary. 53 | var dictionary0 = new HaystackDictionary(); 54 | dictionary0.Add("key", new HaystackString("value")); 55 | dictionary0.AddMarker("someMarker"); 56 | dictionary0.AddNumber("someNumber", 10, "m"); 57 | 58 | // Build a dictionary and remove values as you would a normal Dictionary. 59 | var dictionary1 = new HaystackDictionary 60 | { 61 | ["key"] = new HaystackString("value"), 62 | ["someMarker"] = new HaystackMarker(), 63 | }; 64 | dictionary1.Remove("someMarker"); 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /Examples/Values/HaystackGridExamples.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using ProjectHaystack.Client; 3 | 4 | namespace ProjectHaystack.Examples.Values 5 | { 6 | /// 7 | /// Examples on how to use a HaystackGrid. 8 | /// Note that the rows and metadata inherit HaystackDictionary and can be used as such. 9 | /// 10 | public class HaystackGridExamples 11 | { 12 | private readonly IHaystackClient _haystackClient; 13 | 14 | public HaystackGridExamples(IHaystackClient haystackClient) 15 | { 16 | _haystackClient = haystackClient; 17 | } 18 | 19 | /// 20 | /// Iterate over the grid rows. 21 | /// 22 | public async Task IterateRows() 23 | { 24 | var ops = await _haystackClient.OpsAsync(); 25 | foreach (var row in ops) 26 | { 27 | var allKeys = row.Keys; 28 | var hasVersion = row.ContainsKey("haystackVersion"); 29 | var version = row["haystackVersion"]; 30 | var versionString = (version as HaystackString).Value; 31 | } 32 | } 33 | 34 | /// 35 | /// Select specific grid rows. 36 | /// 37 | public async Task SelectRows() 38 | { 39 | var ops = await _haystackClient.OpsAsync(); 40 | var numRows = ops.RowCount; 41 | var tenthRow = ops[9]; 42 | var secondRow = ops.Row(1); 43 | } 44 | 45 | /// 46 | /// Get the grid meta data. 47 | /// 48 | public async Task GetMeta() 49 | { 50 | var ops = await _haystackClient.OpsAsync(); 51 | var meta = ops.Meta; 52 | var hasKey = meta.ContainsKey("key"); 53 | } 54 | 55 | /// 56 | /// Build a new grid. 57 | /// 58 | public void BuildGrid() 59 | { 60 | // Create the grid. 61 | var grid = new HaystackGrid(); 62 | 63 | // Add columns before adding rows. 64 | 65 | // Add a simple column. 66 | grid.AddColumn("key"); 67 | // Add a column with meta data. 68 | grid.AddColumn("value", new HaystackDictionary { ["meta"] = new HaystackString("value") }); 69 | // Add a column with a configuration method. 70 | grid.AddColumn("details", col => col.Meta.AddMarker("isDetails")); 71 | 72 | // Add a row, make sure it has the same number of parameters as there are columns. 73 | grid.AddRow(new HaystackString("someKey"), new HaystackString("someValue"), new HaystackMarker()); 74 | // Add a row using an array. 75 | grid.AddRow(new HaystackValue[] { new HaystackString("anotherKey"), new HaystackString("anotherValue"), new HaystackNumber(10, "m") }); 76 | 77 | // Add meta data using the default HaystackDictionary functions. 78 | grid.Meta.AddMarker("marker"); 79 | // Add meta data using the AddMeta helper method. 80 | grid.AddMeta("key", new HaystackString("value")); 81 | } 82 | 83 | /// 84 | /// Build a new grid using chaining. 85 | /// 86 | public void BuildGridChained() 87 | { 88 | // Create the grid. 89 | var grid = new HaystackGrid() 90 | .AddColumn("key") 91 | .AddColumn("value", new HaystackDictionary { ["meta"] = new HaystackString("value") }) 92 | .AddColumn("details", col => col.Meta.AddMarker("isDetails")) 93 | .AddRow(new HaystackString("someKey"), new HaystackString("someValue"), new HaystackMarker()) 94 | .AddRow(new HaystackValue[] { new HaystackString("anotherKey"), new HaystackString("anotherValue"), new HaystackNumber(10, "m") }) 95 | .AddMeta("marker", new HaystackMarker()) 96 | .AddMeta("key", new HaystackString("value")); 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /GitVersion.yml: -------------------------------------------------------------------------------- 1 | mode: Mainline 2 | -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Client/IHAsyncClient.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | namespace ProjectHaystack.Client 5 | { 6 | public interface IHAsyncClient : IHClient, IHProj 7 | { 8 | Task EvalAllAsync(HGrid req, bool bChecked); 9 | Task GetStringAsync(string op, Dictionary @params, string mimeRequest = "text/zinc", string mimeResponse = "text/zinc"); 10 | Task PostStringAsync(string op, string req, string mimeRequest = "text/zinc", string mimeResponse = "text/zinc"); 11 | Task readAllAsync(string filter, int limit); 12 | Task readAsync(string filter, bool bChecked); 13 | Task hisWriteAsync(HRef id, HHisItem[] items); 14 | Task HisWriteAsync(HRef id, HHisItem[] items, HDict metaData = null); 15 | Task HisWriteNoWarnAsync(HRef id, HHisItem[] items); 16 | } 17 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Client/IHClient.cs: -------------------------------------------------------------------------------- 1 | namespace ProjectHaystack.Client 2 | { 3 | public interface IHClient 4 | { 5 | HDict about(); 6 | HGrid call(string op, HGrid req); 7 | HGrid call(string op, HGrid req, string mimeType); 8 | HGrid eval(string expr); 9 | HGrid[] evalAll(HGrid req, bool bChecked); 10 | HGrid[] evalAll(string[] exprs); 11 | HGrid[] evalAll(string[] exprs, bool bChecked); 12 | HGrid formats(); 13 | HGrid hisRead(HRef id, object range); 14 | void hisWrite(HRef id, HHisItem[] items); 15 | HGrid invokeAction(HRef id, string action, HDict args); 16 | HGrid invokeAction(HRef id, string action, HDict args, string mimetype); 17 | HGrid ops(); 18 | HGrid pointWrite(HRef id, int level, string who, HVal val, HNum dur); 19 | HGrid pointWriteArray(HRef id); 20 | } 21 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/ProjectHaystack - Backup (1).BackCompat.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | ProjectHaystack 6 | ProjectHaystack.Client.BackCompat 7 | true 8 | 2.0.14 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/ProjectHaystack - Backup.BackCompat.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0;netstandard2.1;netstandard2.0 5 | ProjectHaystack 6 | ProjectHaystack.Client.BackCompat 7 | true 8 | 2.0.2 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/ProjectHaystack.BackCompat.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0;net6.0;net5.0;netstandard2.1;netstandard2.0 5 | ProjectHaystack 6 | ProjectHaystack.Client.BackCompat 7 | true 8 | 2.0.2 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/ProjectHaystack.BackCompat.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $id$ 5 | $version$ 6 | $title$ 7 | $authors$ 8 | $author$ 9 | AFL-3.0 10 | https://github.com/Strukton-Worksphere/haystack-csharp 11 | false 12 | $description$ 13 | 14 | Copyright 2017 15 | haystack backward compatibility 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/CHaystackTZDB.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProjectHaystack 4 | { 5 | [Obsolete("Use HaystackTimeZoneDatabase")] 6 | public class CHaystackTZDB 7 | { 8 | public static string[] tzdb = HaystackTimeZoneDatabase.TimeZones; 9 | } 10 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HBin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.io; 3 | using M = ProjectHaystack.HaystackValueMapper; 4 | 5 | namespace ProjectHaystack 6 | { 7 | [Obsolete("Use HaystackBinary")] 8 | public class HBin : HVal 9 | { 10 | public HBin(HaystackBinary source) 11 | { 12 | Source = source; 13 | } 14 | public HaystackBinary Source { get; } 15 | public string mime => Source.Mime; 16 | public static HBin make(string strMime) => M.Map(new HaystackBinary(strMime)); 17 | public override int GetHashCode() => mime.GetHashCode(); 18 | public override bool Equals(object that) => that != null && that is HBin dict && Source.Equals(M.Map(dict)); 19 | public override string toZinc() => ZincWriter.ToZinc(Source); 20 | public override string toJson() => HaysonWriter.ToHayson(Source); 21 | } 22 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HBool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.io; 3 | using M = ProjectHaystack.HaystackValueMapper; 4 | 5 | namespace ProjectHaystack 6 | { 7 | [Obsolete("Use HaystackBoolean")] 8 | public class HBool : HVal 9 | { 10 | public static readonly HBool TRUE = new HBool(true); 11 | public static readonly HBool FALSE = new HBool(false); 12 | public HBool(HaystackBoolean source) 13 | { 14 | Source = source; 15 | } 16 | private HBool(bool val) 17 | { 18 | Source = new HaystackBoolean(val); 19 | } 20 | public HaystackBoolean Source { get; } 21 | public static HBool make(bool bVal) => new HBool(new HaystackBoolean(bVal)); 22 | public override int GetHashCode() => Source.GetHashCode(); 23 | public override bool Equals(object that) => that != null && that is HBool @bool && Source.Equals(M.Map(@bool)); 24 | public bool val => Source.Value; 25 | public override string ToString() => Source.Value.ToString(); 26 | public override string toJson() => HaysonWriter.ToHayson(Source); 27 | public override string toZinc() => ZincWriter.ToZinc(Source); 28 | } 29 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HCol.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using M = ProjectHaystack.HaystackValueMapper; 3 | 4 | namespace ProjectHaystack 5 | { 6 | [Obsolete("Use HaystackColumn")] 7 | public class HCol 8 | { 9 | public HCol(HaystackColumn source) 10 | { 11 | Source = source; 12 | } 13 | public HCol(int iIndex, string name, HDict meta) 14 | { 15 | Source = new HaystackColumn(iIndex, name, M.Map(meta)); 16 | } 17 | public HaystackColumn Source { get; } 18 | public string Name => Source.Name; 19 | public string dis() => Source.Display; 20 | public HDict meta => M.Map(Source.Meta); 21 | public int Index => Source.Index; 22 | public override int GetHashCode() => Name.GetHashCode() ^ meta.GetHashCode(); 23 | public bool hequals(object that) => Equals(that); 24 | public override bool Equals(object that) => that != null && that is HCol col && Source.Equals(M.Map(col)); 25 | } 26 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HCoord.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.io; 3 | using ProjectHaystack.Validation; 4 | using M = ProjectHaystack.HaystackValueMapper; 5 | 6 | namespace ProjectHaystack 7 | { 8 | [Obsolete("Use HaystackCoordinate")] 9 | public class HCoord : HVal 10 | { 11 | public HCoord(HaystackCoordinate source) 12 | { 13 | Source = source; 14 | } 15 | public HaystackCoordinate Source { get; } 16 | public static HCoord make(string s) => M.Map(ZincReader.ReadValue(s)); 17 | public static HCoord make(double dblLat, double dblLng) => M.Map(new HaystackCoordinate((decimal)dblLat, (decimal)dblLng)); 18 | public static bool isLat(double lat) => HaystackValidator.IsLatitude((decimal)lat); 19 | public static bool isLng(double lng) => HaystackValidator.IsLongitude((decimal)lng); 20 | public double lat => (double)Source.Latitude; 21 | public double lng => (double)Source.Longitude; 22 | public int ulat => (int)(Source.Latitude * 1000000); 23 | public int ulng => (int)(Source.Longitude * 1000000); 24 | public override int GetHashCode() => Source.GetHashCode(); 25 | public override bool Equals(object that) => that != null && that is HCoord coord && Source.Equals(M.Map(coord)); 26 | public override string toZinc() => ZincWriter.ToZinc(M.Map(this)); 27 | public override string toJson() => HaysonWriter.ToHayson(M.Map(this)); 28 | } 29 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HDate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using ProjectHaystack.io; 4 | using M = ProjectHaystack.HaystackValueMapper; 5 | 6 | namespace ProjectHaystack 7 | { 8 | [Obsolete("Use HaystackDate")] 9 | public class HDate : HVal 10 | { 11 | public HDate(HaystackDate source) 12 | { 13 | Source = source; 14 | } 15 | private HDate(int year, int month, int day) 16 | { 17 | Source = new HaystackDate(year, month, day); 18 | } 19 | public HaystackDate Source { get; } 20 | public int Year => Source.Value.Year; 21 | public int Month => Source.Value.Month; 22 | public int Day => Source.Value.Day; 23 | public static HDate make(int year, int month, int day) => M.Map(new HaystackDate(year, month, day)); 24 | public static HDate make(DateTime dt) => M.Map(new HaystackDate(dt)); 25 | public static HDate make(string s) 26 | { 27 | DateTime dtParsed = DateTime.Now; 28 | if (!DateTime.TryParseExact(s, "yyyy'-'MM'-'dd", 29 | CultureInfo.InvariantCulture, 30 | DateTimeStyles.None, 31 | out dtParsed)) 32 | { 33 | throw new FormatException("Invalid date string: " + s); 34 | } 35 | return new HDate(dtParsed.Year, dtParsed.Month, dtParsed.Day); 36 | } 37 | public static HDate today() => M.Map(new HaystackDate(DateTime.Today)); 38 | public HDateTime midnight(HTimeZone tz) => M.Map(new HaystackDateTime(Source.Value, M.Map(tz))); 39 | public override int GetHashCode() => Source.GetHashCode(); 40 | public override bool Equals(object that) => that != null && that is HDate date && Source.Equals(M.Map(date)); 41 | public override string toZinc() => ZincWriter.ToZinc(M.Map(this)); 42 | public override string toJson() => HaysonWriter.ToHayson(M.Map(this)); 43 | public HDate plusDays(int numDays) => M.Map(new HaystackDate(Source.Value.AddDays(numDays))); 44 | public HDate minusDays(int numDays) => M.Map(new HaystackDate(Source.Value.AddDays(-numDays))); 45 | public static bool isLeapYear(int year) => DateTime.IsLeapYear(year); 46 | public DayOfWeek weekday() => Source.Value.DayOfWeek; 47 | public DateTime ToDateTime() => Source.Value; 48 | } 49 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HDateTime.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.io; 3 | using M = ProjectHaystack.HaystackValueMapper; 4 | 5 | namespace ProjectHaystack 6 | { 7 | [Obsolete("Use HaystackDateTime")] 8 | public class HDateTime : HVal 9 | { 10 | public HDateTime(HaystackDateTime source) 11 | { 12 | Source = source; 13 | } 14 | public HaystackDateTime Source { get; } 15 | public HDate date => HDate.make(Source.Value.DateTime.Date); 16 | public HTime time => new HTime(Source.Value.DateTime.TimeOfDay); 17 | public TimeSpan Offset => Source.Value.Offset; 18 | public HTimeZone TimeZone => M.Map(Source.TimeZone); 19 | public long Ticks => Source.Value.Ticks; 20 | public DateTimeOffset CopyOfDTO => Source.Value; 21 | public static HDateTime make(HDate date, HTime time, HTimeZone tz) => M.Map(new HaystackDateTime(M.Map(date), M.Map(time), M.Map(tz))); 22 | public static HDateTime make(int year, int month, int day, int hour, int min, int sec, HTimeZone tz) 23 | => M.Map(new HaystackDateTime(new DateTime(year, month, day, hour, min, sec), M.Map(tz))); 24 | public static HDateTime make(int year, int month, int day, int hour, int min, HTimeZone tz) 25 | => M.Map(new HaystackDateTime(new DateTime(year, month, day, hour, min, 0), M.Map(tz))); 26 | public static HDateTime make(long ticks) 27 | => M.Map(new HaystackDateTime(new DateTime(ticks), HaystackTimeZone.UTC)); 28 | public static HDateTime make(long ticks, HTimeZone tz) 29 | => M.Map(new HaystackDateTime(new DateTime(ticks), M.Map(tz))); 30 | public static HDateTime make(string s, bool bException) 31 | => M.Checked(() => M.Map(ZincReader.ReadValue(s)), bException); 32 | public static HDateTime now(HTimeZone tz) => M.Map(new HaystackDateTime(DateTime.Now, M.Map(tz))); 33 | public static HDateTime now() => M.Map(new HaystackDateTime(DateTime.Now, HaystackTimeZone.UTC)); 34 | public override string toZinc() => ZincWriter.ToZinc(M.Map(this)); 35 | public override string toJson() => HaysonWriter.ToHayson(M.Map(this)); 36 | public override int GetHashCode() => Source.GetHashCode(); 37 | public override bool Equals(object that) => that != null && that is HDateTime dateTime && Source.Equals(M.Map(dateTime)); 38 | public override string ToString() => ZincWriter.ToZinc(M.Map(this)); 39 | public int CompareTo(HDateTime that) => Source.Value.ToUniversalTime().CompareTo(that.Source.Value.ToUniversalTime()); 40 | } 41 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HDateTimeRange.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.io; 3 | using M = ProjectHaystack.HaystackValueMapper; 4 | 5 | namespace ProjectHaystack 6 | { 7 | [Obsolete("Use HaystackDateTimeRange")] 8 | public class HDateTimeRange 9 | { 10 | public HDateTimeRange(HaystackDateTimeRange source) 11 | { 12 | Source = source; 13 | } 14 | public HaystackDateTimeRange Source { get; } 15 | public HDateTime Start => M.Map(Source.Start); 16 | public HDateTime End => M.Map(Source.End); 17 | public static HDateTimeRange make(HDate date, HTimeZone tz) 18 | => M.Map(new HaystackDateTimeRange(new HaystackDateTime(date.Source.Value, M.Map(tz)), new HaystackDateTime(date.Source.Value.AddDays(1), M.Map(tz)))); 19 | public static HDateTimeRange make(HDate start, HDate end, HTimeZone tz) 20 | => M.Map(new HaystackDateTimeRange(new HaystackDateTime(start.Source.Value, M.Map(tz)), new HaystackDateTime(end.Source.Value, M.Map(tz)))); 21 | public static HDateTimeRange make(HDateTime start, HDateTime end) 22 | => M.Map(new HaystackDateTimeRange(M.Map(start), M.Map(end))); 23 | public static HDateTimeRange thisWeek(HTimeZone tz) 24 | { 25 | var firstOfWeek = DateTime.Today.AddDays(DayOfWeek.Sunday - DateTime.Today.DayOfWeek); 26 | return M.Map(new HaystackDateTimeRange( 27 | new HaystackDateTime(firstOfWeek, M.Map(tz)), 28 | new HaystackDateTime(firstOfWeek.AddDays(7), M.Map(tz)))); 29 | } 30 | public static HDateTimeRange thisMonth(HTimeZone tz) 31 | { 32 | var firstOfMonth = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1); 33 | return M.Map(new HaystackDateTimeRange( 34 | new HaystackDateTime(firstOfMonth, M.Map(tz)), 35 | new HaystackDateTime(firstOfMonth.AddMonths(1), M.Map(tz)))); 36 | } 37 | public static HDateTimeRange thisYear(HTimeZone tz) 38 | { 39 | var firstOfYear = new DateTime(DateTime.Today.Year, 1, 1); 40 | return M.Map(new HaystackDateTimeRange( 41 | new HaystackDateTime(firstOfYear, M.Map(tz)), 42 | new HaystackDateTime(firstOfYear.AddYears(1), M.Map(tz)))); 43 | } 44 | public static HDateTimeRange lastWeek(HTimeZone tz) 45 | { 46 | var firstOfWeek = DateTime.Today.AddDays(DayOfWeek.Sunday - DateTime.Today.DayOfWeek).AddDays(-7); 47 | return M.Map(new HaystackDateTimeRange( 48 | new HaystackDateTime(firstOfWeek, M.Map(tz)), 49 | new HaystackDateTime(firstOfWeek.AddDays(7), M.Map(tz)))); 50 | } 51 | public static HDateTimeRange lastMonth(HTimeZone tz) 52 | { 53 | var firstOfMonth = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddMonths(-1); 54 | return M.Map(new HaystackDateTimeRange( 55 | new HaystackDateTime(firstOfMonth, M.Map(tz)), 56 | new HaystackDateTime(firstOfMonth.AddMonths(1), M.Map(tz)))); 57 | } 58 | public static HDateTimeRange lastYear(HTimeZone tz) 59 | { 60 | var firstOfYear = new DateTime(DateTime.Today.Year, 1, 1).AddYears(-1); 61 | return M.Map(new HaystackDateTimeRange( 62 | new HaystackDateTime(firstOfYear, M.Map(tz)), 63 | new HaystackDateTime(firstOfYear.AddYears(1), M.Map(tz)))); 64 | } 65 | public override string ToString() => ZincWriter.ToZinc(Source.Start) + "," + ZincWriter.ToZinc(Source.End); 66 | } 67 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HDef.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.io; 3 | using M = ProjectHaystack.HaystackValueMapper; 4 | 5 | namespace ProjectHaystack 6 | { 7 | [Obsolete("Use HaystackDefinition")] 8 | public class HDef : HVal 9 | { 10 | public HDef(HaystackDefinition source) 11 | { 12 | Source = source; 13 | } 14 | public HaystackDefinition Source { get; } 15 | public static HDef make(string val) => M.Map(ZincReader.ReadValue(val)); 16 | public override int GetHashCode() => Source.GetHashCode(); 17 | public override bool Equals(object that) => that != null && that is HDef date && Source.Equals(M.Map(date)); 18 | public override string toZinc() => ZincWriter.ToZinc(M.Map(this)); 19 | public override string toJson() => HaysonWriter.ToHayson(M.Map(this)); 20 | } 21 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HDict.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using ProjectHaystack.io; 6 | using ProjectHaystack.Validation; 7 | using M = ProjectHaystack.HaystackValueMapper; 8 | 9 | namespace ProjectHaystack 10 | { 11 | [Obsolete("Use HaystackDictionary")] 12 | public class HDict : HVal, IDictionary 13 | { 14 | public HDict(Dictionary map) 15 | { 16 | Source = new HaystackDictionary(map.ToDictionary(kv => kv.Key, kv => M.Map(kv.Value))); 17 | } 18 | public HDict(IDictionary map) 19 | { 20 | Source = new HaystackDictionary(map.ToDictionary(kv => kv.Key, kv => M.Map(kv.Value))); 21 | } 22 | public HDict(HaystackDictionary source) 23 | { 24 | Source = source; 25 | } 26 | public HaystackDictionary Source { get; } 27 | 28 | public static HDict Empty => new HDict(new HaystackDictionary()); 29 | public virtual int Size => Source.Count; 30 | public ICollection Keys => Source.Keys; 31 | public ICollection Values => Source.Values.Select(M.Map).ToArray(); 32 | public int Count => Source.Count; 33 | public virtual bool IsReadOnly => Source.IsReadOnly; 34 | public HVal this[string key] { get => M.Map(Source[key]); set => Source[key] = M.Map(value); } 35 | public virtual int size() => Source.Count; 36 | public bool isEmpty() => Source.IsEmpty(); 37 | public bool has(string name) => Source.ContainsKey(name); 38 | public bool missing(string name) => !Source.ContainsKey(name); 39 | public virtual HVal get(string name) => M.Map(Source.Get(name)); 40 | public virtual HVal get(HCol col, bool bChecked) => M.Checked(() => M.Map(Source.Get(col.Name)), bChecked); 41 | public virtual HVal get(string strName, bool bChecked) => M.Checked(() => M.Map(Source.Get(strName)), bChecked); 42 | // TODO 43 | public HVal getVal(int iIndex, bool bChecked) => M.Checked(() => M.Map(Source.Get(Source.Keys.Skip(iIndex).First())), bChecked); 44 | public virtual string getKeyAt(int iIndex, bool bChecked) => M.Checked(() => Source.Keys.Skip(iIndex).First(), bChecked); 45 | public HRef id() => M.Map(Source.GetReference("id")); 46 | public string dis() => Source.Display; 47 | public bool getBool(string name) => Source.GetBoolean(name); 48 | public string getStr(string name) => Source.GetString(name); 49 | public HRef getRef(string name) => M.Map(Source.GetReference(name)); 50 | public int getInt(string name) => (int)Source.GetDouble(name); 51 | public double getDouble(string name) => Source.GetDouble(name); 52 | public HDef getDef(string name) => M.Map(Source.Get(name)); 53 | public string toString() => ZincWriter.ToZinc(Source); 54 | public override int GetHashCode() => Source.GetHashCode(); 55 | public override bool Equals(object that) => that != null && that is HDict dict && Source.Equals(M.Map(dict)); 56 | public static bool isTagName(string n) => HaystackValidator.IsTagName(n); 57 | public override string toZinc() => ZincWriter.ToZinc(Source); 58 | public override string toJson() => HaysonWriter.ToHayson(Source); 59 | public virtual void Add(string key, HVal value) => Source.Add(key, M.Map(value)); 60 | public bool ContainsKey(string key) => Source.ContainsKey(key); 61 | public virtual bool Remove(string key) => Source.Remove(key); 62 | public bool TryGetValue(string key, out HVal value) 63 | { 64 | if (Source.TryGetValue(key, out var val)) 65 | { 66 | value = M.Map(val); 67 | return true; 68 | } 69 | value = null; 70 | return false; 71 | } 72 | public void Add(KeyValuePair item) => Source.Add(item.Key, M.Map(item.Value)); 73 | public void Clear() => Source.Clear(); 74 | public bool Contains(KeyValuePair item) => Source.Contains(new KeyValuePair(item.Key, M.Map(item.Value))); 75 | public void CopyTo(KeyValuePair[] array, int arrayIndex) 76 | => Source.Select(kv => new KeyValuePair(kv.Key, M.Map(kv.Value))).ToArray().CopyTo(array, arrayIndex); 77 | public bool Remove(KeyValuePair item) => Source.Remove(new KeyValuePair(item.Key, M.Map(item.Value))); 78 | public IEnumerator> GetEnumerator() => Source.Select(kv => new KeyValuePair(kv.Key, M.Map(kv.Value))).GetEnumerator(); 79 | IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 80 | } 81 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HDictBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ProjectHaystack 5 | { 6 | [Obsolete("Use HaystackDict")] 7 | public class HDictBuilder 8 | { 9 | private Dictionary m_map; 10 | 11 | public HDictBuilder () 12 | { 13 | m_map = null; 14 | } 15 | public bool isEmpty() { return size() == 0; } 16 | public int size() { return m_map.Count; } 17 | public bool has(string name) { return get(name, false) != null; } 18 | public bool missing(string name) { return get(name, false) == null; } 19 | public HVal get(string name) { return get(name, true); } 20 | public HVal get(string name, bool bchecked) 21 | { 22 | HVal val = null; 23 | if (m_map.ContainsKey(name)) 24 | val = m_map[name]; 25 | if (val != null) return val; 26 | if (!bchecked) return null; 27 | throw new HaystackUnknownNameException(name); 28 | } 29 | public HDictBuilder add(string name) 30 | { 31 | return add(name, HMarker.VAL); 32 | } 33 | public HDictBuilder add(string name, bool val) 34 | { 35 | return add(name, HBool.make(val)); 36 | } 37 | public HDictBuilder add(string name, long val) 38 | { 39 | return add(name, HNum.make(val)); 40 | } 41 | public HDictBuilder add(string name, long val, String unit) 42 | { 43 | return add(name, HNum.make(val, unit)); 44 | } 45 | public HDictBuilder add(string name, double val) 46 | { 47 | return add(name, HNum.make(val)); 48 | } 49 | public HDictBuilder add(string name, double val, string unit) 50 | { 51 | return add(name, HNum.make(val, unit)); 52 | } 53 | public HDictBuilder add(string name, string val) 54 | { 55 | return add(name, HStr.make(val)); 56 | } 57 | public HDictBuilder add(HDict dict) 58 | { 59 | for (int it = 0; it < dict.size(); it++) 60 | { 61 | string strKey = dict.getKeyAt(it, false); 62 | if (strKey != null) 63 | add(strKey, (HVal)dict.get(strKey,false)); 64 | } 65 | return this; 66 | } 67 | public HDictBuilder add(string name, HVal val) 68 | { 69 | if (!HDict.isTagName(name)) 70 | throw new InvalidOperationException("Invalid tag name: " + name); 71 | if (m_map == null) m_map = new Dictionary(); 72 | m_map.Add(name, val); 73 | return this; 74 | } 75 | public HDict toDict() 76 | { 77 | if (m_map == null || m_map.Count == 0) return HDict.Empty; 78 | HDict dict = new HDict(m_map); 79 | m_map = null; 80 | return dict; 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HGrid.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using ProjectHaystack.io; 7 | using M = ProjectHaystack.HaystackValueMapper; 8 | 9 | namespace ProjectHaystack 10 | { 11 | [Obsolete("Use HaystackGrid")] 12 | public class HGrid : HVal, IEnumerable 13 | { 14 | public HGrid(HaystackGrid source) 15 | { 16 | Source = source; 17 | } 18 | public HaystackGrid Source { get; } 19 | 20 | internal HGrid(HDict meta, List cols, List> rowLists) 21 | { 22 | Source = new HaystackGrid(cols.Select(M.Map).ToList(), rowLists.Select(l => l.Select(M.Map).ToArray()).ToList(), M.Map(meta)); 23 | } 24 | public static HGrid InstanceEmpty { get; } = M.Map(new HaystackGrid()); 25 | 26 | public HDict meta => M.Map(Source.Meta); 27 | public bool isErr() => Source.IsError(); 28 | public bool isEmpty() => Source.IsEmpty(); 29 | public int numRows => Source.RowCount; 30 | public HRow row(int row) => M.Map(Source.Row(row)); 31 | public int numCols => Source.ColumnCount; 32 | public HCol col(int index) => M.Map(Source.Column(index)); 33 | public HCol col(string name) => M.Map(Source.Column(name)); 34 | public HCol col(string name, bool bchecked) => M.Checked(() => M.Map(Source.Column(name)), bchecked); 35 | public override string toZinc() => ZincWriter.ToZinc(Source); 36 | public override string toJson() => HaysonWriter.ToHayson(Source); 37 | public override int GetHashCode() => Source.GetHashCode(); 38 | public override bool Equals(object that) => that != null && that is HGrid grid && Source.Equals(M.Map(grid)); 39 | public void dump() 40 | { 41 | Debug.WriteLine(ZincWriter.ToZinc(Source)); 42 | Debug.Flush(); 43 | } 44 | public void dumpToConsole() 45 | { 46 | Console.WriteLine(ZincWriter.ToZinc(Source)); 47 | } 48 | public string dumpAsString() => ZincWriter.ToZinc(Source); 49 | public IEnumerable Cols => Source.Columns.Select(M.Map); 50 | public IEnumerable Rows => Source.Rows.Select(M.Map); 51 | public IEnumerator GetEnumerator() => Source.Select(M.Map).GetEnumerator(); 52 | IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 53 | } 54 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HHisItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using M = ProjectHaystack.HaystackValueMapper; 4 | 5 | namespace ProjectHaystack 6 | { 7 | [Obsolete("Use HaystackHistoryItem")] 8 | public class HHisItem : HDict 9 | { 10 | public HHisItem(HaystackHistoryItem source) 11 | : base(ToDictionary(source)) 12 | { 13 | Source = source; 14 | } 15 | 16 | public HaystackHistoryItem Source { get; } 17 | public HDateTime TimeStamp => M.Map(Source.TimeStamp); 18 | public HVal hsVal => M.Map(Source.Value); 19 | public int hsize() { return 2; } 20 | public static HHisItem[] gridToItems(HGrid grid) => HaystackHistoryItem.ReadGrid(M.Map(grid)).Select(M.Map).ToArray(); 21 | public static HHisItem make(HDateTime ts, HVal val) => M.Map(new HaystackHistoryItem(M.Map(ts), M.Map(val))); 22 | public override HVal get(string name, bool bchecked) 23 | { 24 | if (name.CompareTo("ts") == 0) return TimeStamp; 25 | if (name.CompareTo("val") == 0) return hsVal; 26 | if (!bchecked) return null; 27 | throw new HaystackUnknownNameException("Name not known: " + name); 28 | } 29 | 30 | private static HaystackDictionary ToDictionary(HaystackHistoryItem source) 31 | { 32 | var dict = new HaystackDictionary(); 33 | dict.Add("ts", source.TimeStamp); 34 | dict.Add("val", source.Value); 35 | return dict; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using ProjectHaystack.io; 6 | using M = ProjectHaystack.HaystackValueMapper; 7 | 8 | namespace ProjectHaystack 9 | { 10 | [Obsolete("Use HaystackList")] 11 | public class HList : HVal, IEnumerable 12 | { 13 | public HList(HaystackList source) 14 | { 15 | Source = source; 16 | } 17 | public HaystackList Source { get; } 18 | public static HList EMPTY = M.Map(new HaystackList()); 19 | public static HList make(params HVal[] items) => M.Map(new HaystackList(items.Select(M.Map).ToArray())); 20 | public static HList make(List items) => M.Map(new HaystackList(items.Select(M.Map).ToArray())); 21 | public int size() => Source.Count; 22 | public HVal get(int i) => M.Map(Source[i]); 23 | public HVal this[int i] => M.Map(Source[i]); 24 | public bool CompareItems(List items) 25 | { 26 | if (items.Count != Source.Count) return false; 27 | bool bRet = true; 28 | for (int i = 0; i < items.Count; i++) 29 | { 30 | if (!items[i].hequals(M.Map(Source[i]))) 31 | bRet = false; 32 | } 33 | return bRet; 34 | } 35 | public override string toZinc() => ZincWriter.ToZinc(M.Map(this)); 36 | public override string toJson() => HaysonWriter.ToHayson(M.Map(this)); 37 | public override int GetHashCode() => Source.GetHashCode(); 38 | public override bool Equals(object that) => that != null && that is HList list && Source.Equals(M.Map(list)); 39 | public IEnumerator GetEnumerator() => Source.Select(M.Map).GetEnumerator(); 40 | IEnumerator IEnumerable.GetEnumerator() => Source.Select(M.Map).GetEnumerator(); 41 | } 42 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HMarker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using M = ProjectHaystack.HaystackValueMapper; 3 | 4 | namespace ProjectHaystack 5 | { 6 | [Obsolete("Use HaystackMarker")] 7 | public class HMarker : HVal 8 | { 9 | public HMarker(HaystackMarker source) 10 | { 11 | Source = source; 12 | } 13 | public HaystackMarker Source { get; } 14 | public static readonly HMarker VAL = M.Map(new HaystackMarker()); 15 | 16 | public override int GetHashCode() => Source.GetHashCode(); 17 | public override bool Equals(object that) => that != null && that is HMarker; 18 | public override string ToString() { return "marker"; } 19 | public override string toJson() { return "m:"; } 20 | public override string toZinc() { return "M"; } 21 | } 22 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HNA.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using M = ProjectHaystack.HaystackValueMapper; 3 | 4 | namespace ProjectHaystack 5 | { 6 | [Obsolete("Use HaystackNotAvailable")] 7 | public class HNA : HVal 8 | { 9 | public HNA(HaystackNotAvailable source) 10 | { 11 | Source = source; 12 | } 13 | public HaystackNotAvailable Source { get; } 14 | public static HNA VAL = M.Map(new HaystackNotAvailable()); 15 | 16 | public override int GetHashCode() => Source.GetHashCode(); 17 | public override bool Equals(object that) => that != null && that is HNA; 18 | public override string ToString() { return "na"; } 19 | public override string toJson() { return "z:"; } 20 | public override string toZinc() { return "NA"; } 21 | } 22 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HNum.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.io; 3 | using ProjectHaystack.Validation; 4 | using M = ProjectHaystack.HaystackValueMapper; 5 | 6 | namespace ProjectHaystack 7 | { 8 | [Obsolete("Use HaystackNumber")] 9 | public class HNum : HVal 10 | { 11 | public HNum(HaystackNumber source) 12 | { 13 | Source = source; 14 | } 15 | public HaystackNumber Source { get; } 16 | public double doubleval => Source.Value; 17 | public string unit => Source.Unit; 18 | public static HNum make(int val) => M.Map(new HaystackNumber(val)); 19 | public static HNum make(int val, string unit) => M.Map(new HaystackNumber(val, unit)); 20 | public static HNum make(long val) => M.Map(new HaystackNumber(val)); 21 | public static HNum make(long val, string unit) => M.Map(new HaystackNumber(val, unit)); 22 | public static HNum make(double val) => M.Map(new HaystackNumber(val)); 23 | public static HNum make(double val, string unit) => M.Map(new HaystackNumber(val, unit)); 24 | public static HNum ZERO = M.Map(HaystackNumber.ZERO); 25 | public static HNum POS_INF = M.Map(HaystackNumber.POS_INF); 26 | public static HNum NEG_INF = M.Map(HaystackNumber.NEG_INF); 27 | public static HNum NaN = M.Map(HaystackNumber.NaN); 28 | public override int GetHashCode() => Source.GetHashCode(); 29 | public override bool Equals(object that) => that != null && that is HNum num && Source.Equals(M.Map(num)); 30 | public int compareTo(object that) => that is HNum num ? Source.CompareTo(M.Map(num)) : 1; 31 | public override string toZinc() => ZincWriter.ToZinc(M.Map(this)); 32 | public override string toJson() => HaysonWriter.ToHayson(M.Map(this)); 33 | public long millis() 34 | { 35 | string u = Source.Unit; 36 | if (u == null) u = "null"; 37 | if ((u.Trim() == "ms") || (u.Trim() == "millisecond")) return (long)doubleval; 38 | if ((u.Trim() == "s") || (u.Trim() == "sec")) return (long)(doubleval * 1000.0); // NOTE: A case was taken out of the Java here - it represented an unreachable test 39 | if ((u.Trim() == "min") || (u.Trim() == "minute")) return (long)(doubleval * 1000.0 * 60.0); 40 | if ((u.Trim() == "h") || (u.Trim() == "hr")) return (long)(doubleval * 1000.0 * 3600.0); // NOTE: A case was taken out of the Java here - it represented an unreachable test 41 | throw new InvalidOperationException("Invalid duration unit: " + u); 42 | } 43 | public static bool isUnitName(string strUnit) => HaystackValidator.IsUnitName(strUnit); 44 | } 45 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HRef.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.io; 3 | using ProjectHaystack.Validation; 4 | using M = ProjectHaystack.HaystackValueMapper; 5 | 6 | namespace ProjectHaystack 7 | { 8 | [Obsolete("Use HaystackReference")] 9 | public class HRef : HVal 10 | { 11 | public HRef(HaystackReference source) 12 | { 13 | Source = source; 14 | } 15 | public HaystackReference Source { get; } 16 | public string val => Source.Value; 17 | public bool disSet => Source.Display != null; 18 | public static HRef make(string val, string dis) => M.Map(new HaystackReference(val, dis)); 19 | public static HRef make(string val) => M.Map(new HaystackReference(val)); 20 | public override int GetHashCode() => Source.GetHashCode(); 21 | public override bool Equals(object that) => that != null && that is HRef str && Source.Equals(M.Map(str)); 22 | public string display() => Source.Display; 23 | public string toCode() => "@" + Source.Value; 24 | public override string toZinc() => ZincWriter.ToZinc(M.Map(this)); 25 | public override string ToString() => Source.Value; 26 | public override string toJson() => HaysonWriter.ToHayson(M.Map(this)); 27 | public static bool isId(string id) => HaystackValidator.IsReferenceId(id); 28 | public static bool isIdChar(int ch) => HaystackValidator.IsReferenceIdChar((char)ch); 29 | public static HRef nullRef = M.Map(new HaystackReference(null)); 30 | } 31 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HRemove.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.io; 3 | using M = ProjectHaystack.HaystackValueMapper; 4 | 5 | namespace ProjectHaystack 6 | { 7 | [Obsolete("Use HaystackRemove")] 8 | public class HRemove : HVal 9 | { 10 | public HRemove(HaystackRemove source) 11 | { 12 | Source = source; 13 | } 14 | public static HRemove VAL = M.Map(new HaystackRemove()); 15 | public HaystackRemove Source { get; } 16 | public override int GetHashCode() => Source.GetHashCode(); 17 | public override bool Equals(object that) => that != null && that is HRemove; 18 | public override string toZinc() => ZincWriter.ToZinc(M.Map(this)); 19 | public override string toJson() => HaysonWriter.ToHayson(M.Map(this)); 20 | } 21 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HRow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using M = ProjectHaystack.HaystackValueMapper; 3 | 4 | namespace ProjectHaystack 5 | { 6 | [Obsolete("Use HaystackRow")] 7 | public class HRow : HDict 8 | { 9 | public HRow(HaystackRow source) 10 | : base(source) 11 | { 12 | Source = source; 13 | } 14 | public HaystackRow Source { get; } 15 | public HGrid Grid => M.Map(Source.Grid); 16 | public HDict ToDict() => M.Map(Source); 17 | public override void Add(string key, HVal value) => Source.Add(key, M.Map(value)); 18 | public override bool Remove(string key) => Source.Remove(key); 19 | } 20 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HStr.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.io; 3 | using M = ProjectHaystack.HaystackValueMapper; 4 | 5 | namespace ProjectHaystack 6 | { 7 | [Obsolete("Use HaystackString")] 8 | public class HStr : HVal 9 | { 10 | public HStr(HaystackString source) 11 | { 12 | Source = source; 13 | } 14 | protected HStr(string val) 15 | { 16 | Source = new HaystackString(val); 17 | } 18 | public HaystackString Source { get; } 19 | public static HStr InstanceEmpty => M.Map(HaystackString.Empty); 20 | public static HStr make(string val) => M.Map(new HaystackString(val)); 21 | public string Value => Source.Value; 22 | 23 | public override int GetHashCode() => Source.GetHashCode(); 24 | public override bool Equals(object that) => that != null && that is HStr str && Source.Equals(M.Map(str)); 25 | public override string toZinc() => ZincWriter.ToZinc(M.Map(this)); 26 | public override string toJson() => HaysonWriter.ToHayson(M.Map(this)); 27 | public static string toCode(string val) => ZincWriter.ToZinc(new HaystackString(val)); 28 | public static string[] customSplitWithTrim(string str, char[] cSeps, bool bEmpty) 29 | { 30 | string[] strARet; 31 | if (bEmpty) 32 | strARet = str.Split(cSeps, StringSplitOptions.RemoveEmptyEntries); 33 | else 34 | strARet = str.Split(cSeps); 35 | for (int i = 0; i < strARet.Length; i++) 36 | strARet[i] = strARet[i].Trim(); 37 | return strARet; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HTime.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.io; 3 | using M = ProjectHaystack.HaystackValueMapper; 4 | 5 | namespace ProjectHaystack 6 | { 7 | [Obsolete("Use HaystackTime")] 8 | public class HTime : HVal 9 | { 10 | public HTime(HaystackTime source) 11 | { 12 | Source = source; 13 | } 14 | public HTime(TimeSpan time) 15 | { 16 | Source = new HaystackTime(time); 17 | } 18 | public HaystackTime Source { get; } 19 | public int Hour => Source.Value.Hours; 20 | public int Minute => Source.Value.Minutes; 21 | public int Second => Source.Value.Seconds; 22 | public int Millisecond => Source.Value.Milliseconds; 23 | 24 | public static HTime make(int hour, int min, int sec, int ms) 25 | { 26 | if (hour < 0 || hour > 23) throw new ArgumentException("Invalid hour", "hour"); 27 | if (min < 0 || min > 59) throw new ArgumentException("Invalid min", "min"); 28 | if (sec < 0 || sec > 59) throw new ArgumentException("Invalid sec", "sec"); 29 | if (ms < 0 || ms > 999) throw new ArgumentException("Invalid ms", "ms"); 30 | return new HTime(new TimeSpan(0, hour, min, sec, ms)); 31 | } 32 | public static HTime make(int hour, int min, int sec) 33 | { 34 | return make(hour, min, sec, 0); 35 | } 36 | public static HTime make(int hour, int min) 37 | { 38 | return make(hour, min, 0, 0); 39 | } 40 | public static HTime make(DateTime dt) => M.Map(new HaystackTime(dt.TimeOfDay)); 41 | public static HTime make(string s) => M.Map(ZincReader.ReadValue(s)); 42 | public static readonly HTime MIDNIGHT = new HTime(TimeSpan.Zero); 43 | public override int GetHashCode() => Source.GetHashCode(); 44 | public override bool Equals(object that) => that != null && that is HTime time && Source.Equals(M.Map(time)); 45 | public override int CompareTo(object obj) => obj is HTime time ? Source.CompareTo(M.Map(time)) : -1; 46 | public override string toZinc() => ZincWriter.ToZinc(M.Map(this)); 47 | public override string toJson() => HaysonWriter.ToHayson(M.Map(this)); 48 | public override bool hequals(object that) => Equals(that); 49 | } 50 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HTimeZone.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using M = ProjectHaystack.HaystackValueMapper; 3 | 4 | namespace ProjectHaystack 5 | { 6 | [Obsolete("Use HaystackTimeZone")] 7 | public class HTimeZone 8 | { 9 | public HTimeZone(HaystackTimeZone source) 10 | { 11 | Source = source; 12 | } 13 | public HaystackTimeZone Source { get; } 14 | public static HTimeZone make(string name, bool bChecked) => M.Checked(() => M.Map(new HaystackTimeZone(name)), bChecked); 15 | public static HTimeZone make(TimeZoneInfo dntzi, bool bChecked) => M.Checked(() => M.Map(new HaystackTimeZone(dntzi)), bChecked); 16 | public bool hequals(object that) => that != null && that is HTimeZone tz && Source.Equals(M.Map(tz)); 17 | public TimeZoneInfo dntz => Source.TimeZoneInfo; 18 | public static HTimeZone UTC => M.Map(HaystackTimeZone.UTC); 19 | public static HTimeZone REL => M.Map(HaystackTimeZone.REL); 20 | public static HTimeZone Default => M.Map(new HaystackTimeZone(TimeZoneInfo.Local.Id)); 21 | public override string ToString() => Source.Name; 22 | } 23 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HUri.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.io; 3 | using M = ProjectHaystack.HaystackValueMapper; 4 | 5 | namespace ProjectHaystack 6 | { 7 | [Obsolete("Use HaystackUri")] 8 | public class HUri : HVal 9 | { 10 | public HUri(HaystackUri source) 11 | { 12 | Source = source; 13 | } 14 | public HaystackUri Source { get; } 15 | public string UriVal => Source.Value; 16 | public static HUri make(string val) => M.Map(new HaystackUri(val)); 17 | public override int GetHashCode() => Source.GetHashCode(); 18 | public override bool Equals(object that) => that != null && that is HUri uri && Source.Equals(M.Map(uri)); 19 | public override string toZinc() => ZincWriter.ToZinc(M.Map(this)); 20 | public override string toJson() => HaysonWriter.ToHayson(M.Map(this)); 21 | } 22 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HVal.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProjectHaystack 4 | { 5 | [Obsolete("Use HaystackValue")] 6 | public abstract class HVal : IComparable 7 | { 8 | public HVal() { } 9 | public override string ToString() { return toZinc(); } 10 | public abstract string toZinc(); 11 | public abstract string toJson(); 12 | public virtual bool hequals(object that) => Equals(that); 13 | public virtual int hashCode() => GetHashCode(); 14 | public virtual int CompareTo(object obj) 15 | { 16 | return ToString().CompareTo(obj.ToString()); 17 | } 18 | 19 | public static bool operator ==(HVal left, HVal right) => Equals(left, null) ? Equals(right, null) : left.Equals(right); 20 | public static bool operator !=(HVal left, HVal right) => !(left == right); 21 | } 22 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/HXStr.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.io; 3 | using ProjectHaystack.Validation; 4 | using M = ProjectHaystack.HaystackValueMapper; 5 | 6 | namespace ProjectHaystack 7 | { 8 | [Obsolete("Use HaystackXString")] 9 | public class HXStr : HVal 10 | { 11 | public HXStr(HaystackXString source) 12 | { 13 | Source = source; 14 | } 15 | 16 | public HaystackXString Source { get; } 17 | public string Type => Source.Type; 18 | public string Val => Source.Value; 19 | public static HVal decode(string type, string val) 20 | { 21 | if ("Bin".CompareTo(type) == 0) return HBin.make(val); 22 | return M.Map(new HaystackXString(val, type)); 23 | } 24 | public static HXStr encode(object val) 25 | { 26 | return M.Map(new HaystackXString(nameof(val), val.ToString())); 27 | } 28 | private static bool isValidType(string t) => HaystackValidator.IsTypeName(t); 29 | public override string toZinc() => ZincWriter.ToZinc(M.Map(this)); 30 | public override string toJson() => HaysonWriter.ToHayson(M.Map(this)); 31 | public override int GetHashCode() => Source.GetHashCode(); 32 | public override bool Equals(object that) => that != null && that is HXStr str && Source.Equals(M.Map(str)); 33 | } 34 | } -------------------------------------------------------------------------------- /ProjectHaystack.BackCompat/Values/IHProj.cs: -------------------------------------------------------------------------------- 1 | namespace ProjectHaystack 2 | { 3 | public interface IHProj 4 | { 5 | HDict about(); 6 | HGrid hisRead(HRef id, object range); 7 | void hisWrite(HRef id, HHisItem[] items); 8 | HGrid readAll(string filter, int limit); 9 | HDict readById(HRef id, bool bChecked); 10 | HGrid readByIds(HRef[] ids, bool bChecked); 11 | } 12 | } -------------------------------------------------------------------------------- /ProjectHaystack/Auth/AutodetectAuthenticator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Net.Http; 4 | using System.Net.Http.Headers; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace ProjectHaystack.Auth 9 | { 10 | /// 11 | /// Authentication mechanism that tries to auto-detect the Haystack authentication mechanism. 12 | /// 13 | public class AutodetectAuthenticator : IAuthenticator 14 | { 15 | private readonly string _username; 16 | private readonly string _password; 17 | private const string _wwwAuthenticateHeader = "WWW-Authenticate"; 18 | 19 | public AutodetectAuthenticator(string username, string password) 20 | { 21 | _username = username; 22 | _password = password; 23 | } 24 | 25 | public async Task Authenticate(HttpClient client, Uri authUrl) 26 | { 27 | var authenticator = await SendHello(client, authUrl).ConfigureAwait(false); 28 | await authenticator.Authenticate(client, authUrl); 29 | } 30 | 31 | private async Task SendHello(HttpClient client, Uri authUrl) 32 | { 33 | var message = new HttpRequestMessage(HttpMethod.Get, authUrl); 34 | message.Headers.Authorization = new AuthenticationHeaderValue("HELLO", 35 | "username=" + Convert.ToBase64String(Encoding.UTF8.GetBytes(_username)).Trim('=')); 36 | using (var response = await client.SendAsync(message)) 37 | { 38 | string auth = null; 39 | try 40 | { 41 | auth = response.Headers.GetValues(_wwwAuthenticateHeader).First(); 42 | } 43 | catch (InvalidOperationException) 44 | { 45 | throw new InvalidOperationException($"Cannot get authentication header, server response was: {(int)response.StatusCode}"); 46 | } 47 | 48 | var authLower = auth.ToLower(); 49 | 50 | if (authLower.StartsWith("basic")) 51 | return new BasicAuthenticator(_username, _password); 52 | 53 | if (authLower.StartsWith("scram")) 54 | return new ScramAuthenticator(_username, _password); 55 | 56 | throw new InvalidOperationException($"Autodetect cannot determine authentication type from authentication header: {auth}"); 57 | } 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /ProjectHaystack/Auth/BasicAuthenticator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Net.Http; 6 | using System.Net.Http.Headers; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace ProjectHaystack.Auth 11 | { 12 | /// 13 | /// Authentication method using HayStack Basic authentication. 14 | /// 15 | public class BasicAuthenticator : IAuthenticator 16 | { 17 | private readonly string _username; 18 | private readonly string _password; 19 | private const string _wwwAuthenticateHeader = "WWW-Authenticate"; 20 | 21 | public BasicAuthenticator(string username, string password) 22 | { 23 | _username = username; 24 | _password = password; 25 | } 26 | 27 | public async Task Authenticate(HttpClient client, Uri authUrl) 28 | { 29 | await SendHello(client, authUrl).ConfigureAwait(false); 30 | await SendFinal(client, authUrl).ConfigureAwait(false); 31 | } 32 | 33 | private async Task SendHello(HttpClient client, Uri authUrl) 34 | { 35 | var message = new HttpRequestMessage(HttpMethod.Get, authUrl); 36 | message.Headers.Authorization = new AuthenticationHeaderValue("HELLO", 37 | "username=" + Convert.ToBase64String(Encoding.UTF8.GetBytes(_username)).Trim('=')); 38 | using (var response = await client.SendAsync(message)) 39 | { 40 | // https://project-haystack.org/doc/docHaystack/Auth 41 | // If multiple authentication mechanisms are supported, the server SHOULD specify them in order of most preferred to least preferred. 42 | // So, we need to check all of them. 43 | // Header example: SCRAM hash=SHA-256, handshakeToken=aabbcc, PLAINTEXT, BASIC 44 | IEnumerable auth = null; 45 | try 46 | { 47 | auth = response.Headers.GetValues(_wwwAuthenticateHeader); 48 | } 49 | catch (InvalidOperationException) 50 | { 51 | throw new InvalidOperationException($"Cannot get authentication header, server response was: {(int)response.StatusCode}"); 52 | } 53 | if (auth.Any(x => x.StartsWith("basic", StringComparison.OrdinalIgnoreCase))) 54 | return; 55 | 56 | string server = response.Headers.Contains("Server") ? (response.Headers.GetValues("Server").FirstOrDefault()?.ToLower() ?? string.Empty) : string.Empty; 57 | // fallback to basic if server says it's Niagara; Niagara 4.6 return empry WWW-Authenticate and Server headers 58 | if (server.StartsWith("niagara", StringComparison.Ordinal) || (response.StatusCode == HttpStatusCode.Unauthorized && (auth.Count() == 0 || auth.All(x => string.IsNullOrEmpty(x))) && string.IsNullOrEmpty(server))) 59 | return; 60 | 61 | // detect N4 by their bug - lolol 62 | var content = await response.Content.ReadAsStringAsync(); 63 | if (response.StatusCode == HttpStatusCode.InternalServerError && content != null && content.Contains("wrong 4-byte ending")) 64 | return; 65 | 66 | throw new InvalidOperationException("Invalid reponse on basic authentication request"); 67 | } 68 | } 69 | 70 | private async Task SendFinal(HttpClient client, Uri authUrl) 71 | { 72 | try 73 | { 74 | var message = new HttpRequestMessage(HttpMethod.Get, authUrl); 75 | message.Headers.Authorization = new AuthenticationHeaderValue("Basic", 76 | Convert.ToBase64String(Encoding.UTF8.GetBytes(_username + ":" + _password)).Trim('=')); 77 | using (var response = await client.SendAsync(message)) 78 | { 79 | if ((int)response.StatusCode != 200) 80 | { 81 | throw new HaystackAuthException("Basic auth failed: " + response.StatusCode + " " + (await response.Content.ReadAsStringAsync())); 82 | } 83 | } 84 | 85 | // Set default Authorization header for following requests 86 | client.DefaultRequestHeaders.Authorization = message.Headers.Authorization; 87 | } 88 | catch (Exception e) 89 | { 90 | throw new HaystackAuthException("basic authentication failed", e); 91 | } 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /ProjectHaystack/Auth/IAuthenticator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | 5 | namespace ProjectHaystack.Auth 6 | { 7 | /// 8 | /// Defines an authentication mechanism using a HttpClient. 9 | /// 10 | public interface IAuthenticator 11 | { 12 | Task Authenticate(HttpClient client, Uri authUrl); 13 | } 14 | } -------------------------------------------------------------------------------- /ProjectHaystack/Auth/NonHaystackBasicAuthenticator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using System.Net.Http.Headers; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ProjectHaystack.Auth 8 | { 9 | /// 10 | /// Authentication mechanism using non-Haystack simple Basic authentication. 11 | /// 12 | public class NonHaystackBasicAuthenticator : IAuthenticator 13 | { 14 | private readonly string _username; 15 | private readonly string _password; 16 | 17 | public NonHaystackBasicAuthenticator(string username, string password) 18 | { 19 | _username = username; 20 | _password = password; 21 | } 22 | 23 | public async Task Authenticate(HttpClient client, Uri authUrl) 24 | { 25 | client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", 26 | Convert.ToBase64String(Encoding.UTF8.GetBytes(_username + ":" + _password)).Trim('=')); 27 | try 28 | { 29 | using (var response = await client.GetAsync(authUrl)) 30 | { 31 | if ((int)response.StatusCode != 200) 32 | { 33 | throw new HaystackAuthException("Basic auth failed: " + response.StatusCode + " " + (await response.Content.ReadAsStringAsync())); 34 | } 35 | } 36 | } 37 | catch (Exception e) 38 | { 39 | throw new HaystackAuthException("basic authentication failed", e); 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /ProjectHaystack/Builders/HaystackDateTimeRangeBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | 4 | namespace ProjectHaystack.Builders 5 | { 6 | public class HaystackDateTimeRangeBuilder 7 | { 8 | private readonly HaystackTimeZone _timeZone; 9 | private readonly Func _currentTimeProvider; 10 | private readonly CultureInfo _cultureInfo; 11 | 12 | public HaystackDateTimeRangeBuilder(HaystackTimeZone timeZone, Func currentTimeProvider, CultureInfo cultureInfo) 13 | { 14 | _timeZone = timeZone; 15 | _currentTimeProvider = currentTimeProvider; 16 | _cultureInfo = cultureInfo; 17 | } 18 | 19 | public HaystackDateTimeRangeBuilder(HaystackTimeZone timeZone) : this(timeZone, () => DateTime.Now, CultureInfo.InvariantCulture) 20 | { 21 | } 22 | 23 | public HaystackDateTimeRange Today() 24 | { 25 | var currentTime = _currentTimeProvider(); 26 | var start = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day); 27 | return new HaystackDateTimeRange( 28 | new HaystackDateTime(start, _timeZone), 29 | new HaystackDateTime(start.AddDays(1), _timeZone)); 30 | } 31 | 32 | public HaystackDateTimeRange Yesterday() 33 | { 34 | var currentTime = _currentTimeProvider(); 35 | var start = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day).AddDays(-1); 36 | return new HaystackDateTimeRange( 37 | new HaystackDateTime(start, _timeZone), 38 | new HaystackDateTime(start.AddDays(1), _timeZone)); 39 | } 40 | 41 | public HaystackDateTimeRange ThisWeek() 42 | { 43 | var currentTime = _currentTimeProvider(); 44 | int diff = (7 + (currentTime.DayOfWeek - _cultureInfo.DateTimeFormat.FirstDayOfWeek)) % 7; 45 | var start = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day).AddDays(-1 * diff); 46 | return new HaystackDateTimeRange( 47 | new HaystackDateTime(start, _timeZone), 48 | new HaystackDateTime(start.AddDays(7), _timeZone)); 49 | } 50 | 51 | public HaystackDateTimeRange LastWeek() 52 | { 53 | var currentTime = _currentTimeProvider(); 54 | int diff = (7 + (currentTime.DayOfWeek - _cultureInfo.DateTimeFormat.FirstDayOfWeek)) % 7; 55 | var start = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day).AddDays(-1 * diff - 7); 56 | return new HaystackDateTimeRange( 57 | new HaystackDateTime(start, _timeZone), 58 | new HaystackDateTime(start.AddDays(7), _timeZone)); 59 | } 60 | public HaystackDateTimeRange ThisMonth() 61 | { 62 | var currentTime = _currentTimeProvider(); 63 | var start = new DateTime(currentTime.Year, currentTime.Month, 1); 64 | return new HaystackDateTimeRange( 65 | new HaystackDateTime(start, _timeZone), 66 | new HaystackDateTime(start.AddMonths(1), _timeZone)); 67 | } 68 | 69 | public HaystackDateTimeRange LastMonth() 70 | { 71 | var currentTime = _currentTimeProvider(); 72 | var start = new DateTime(currentTime.Year, currentTime.Month, 1).AddMonths(-1); 73 | return new HaystackDateTimeRange( 74 | new HaystackDateTime(start, _timeZone), 75 | new HaystackDateTime(start.AddMonths(1), _timeZone)); 76 | } 77 | 78 | public HaystackDateTimeRange ThisYear() 79 | { 80 | var currentTime = _currentTimeProvider(); 81 | var start = new DateTime(currentTime.Year, 1, 1); 82 | return new HaystackDateTimeRange( 83 | new HaystackDateTime(start, _timeZone), 84 | new HaystackDateTime(start.AddYears(1), _timeZone)); 85 | } 86 | 87 | public HaystackDateTimeRange LastYear() 88 | { 89 | var currentTime = _currentTimeProvider(); 90 | var start = new DateTime(currentTime.Year, 1, 1).AddYears(-1); 91 | return new HaystackDateTimeRange( 92 | new HaystackDateTime(start, _timeZone), 93 | new HaystackDateTime(start.AddYears(1), _timeZone)); 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /ProjectHaystack/Exceptions/HaystackAuthException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProjectHaystack 4 | { 5 | /// 6 | /// Exception which is thrown by the authentication framework if an error occurs while trying 7 | /// to authenticat a user. 8 | /// 9 | public class HaystackAuthException : Exception 10 | { 11 | public HaystackAuthException(string s) 12 | : base(s) { } 13 | 14 | public HaystackAuthException(string s, Exception throwable) 15 | : base(s, throwable) { } 16 | } 17 | } -------------------------------------------------------------------------------- /ProjectHaystack/Exceptions/HaystackException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProjectHaystack 4 | { 5 | /// 6 | /// Exception thrown when a grid is returned with the err marker tag 7 | /// indicating a server side error. 8 | /// 9 | public class HaystackException : Exception 10 | { 11 | public HaystackGrid Grid { get; private set; } 12 | 13 | public HaystackException(HaystackGrid grid) 14 | : base(ReadStringOrNull(grid, "dis") ?? "server side error") 15 | { 16 | Grid = grid; 17 | } 18 | 19 | public string ReadMessage => ReadStringOrNull(Grid, "dis"); 20 | 21 | /// 22 | /// Read server side stack trace. 23 | /// 24 | /// Stack trace or null. 25 | public string ReadTrace() => ReadStringOrNull(Grid, "errTrace"); 26 | 27 | 28 | private static string ReadStringOrNull(HaystackGrid grid, string tagName) 29 | { 30 | if (!grid.Meta.ContainsKey(tagName)) 31 | { 32 | return null; 33 | } 34 | var dis = grid.Meta[tagName]; 35 | return dis is HaystackString str ? str.Value : null; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /ProjectHaystack/Exceptions/HaystackUnknownNameException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProjectHaystack 4 | { 5 | /// 6 | /// Exception thrown when a checked lookup for a name in a dict or grid finds no such tag. 7 | /// 8 | public class HaystackUnknownNameException : Exception 9 | { 10 | public HaystackUnknownNameException(string message) : base(message) 11 | { 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /ProjectHaystack/Extensions/HaystackDictionaryExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace ProjectHaystack 2 | { 3 | public static class HaystackDictionaryExtensions 4 | { 5 | public static TValue GetUnchecked(this HaystackDictionary dict, string name) 6 | where TValue : HaystackValue 7 | { 8 | if (dict.ContainsKey(name)) 9 | return dict.Get(name); 10 | return null; 11 | } 12 | 13 | public static string GetString(this HaystackDictionary dict, string name) 14 | { 15 | return dict.Get(name).Value; 16 | } 17 | 18 | public static string GetStringUnchecked(this HaystackDictionary dict, string name) 19 | { 20 | return dict.GetUnchecked(name)?.Value; 21 | } 22 | 23 | public static bool GetBoolean(this HaystackDictionary dict, string name) 24 | { 25 | return dict.Get(name).Value; 26 | } 27 | 28 | public static bool GetBooleanUnchecked(this HaystackDictionary dict, string name) 29 | { 30 | return dict.GetNullableBoolean(name) ?? false; 31 | } 32 | 33 | public static bool? GetNullableBoolean(this HaystackDictionary dict, string name) 34 | { 35 | return dict.GetUnchecked(name)?.Value; 36 | } 37 | 38 | public static HaystackReference GetReference(this HaystackDictionary dict, string name) 39 | { 40 | return dict.Get(name); 41 | } 42 | 43 | public static HaystackReference GetReferenceUnchecked(this HaystackDictionary dict, string name) 44 | { 45 | return dict.GetUnchecked(name); 46 | } 47 | 48 | public static double GetDouble(this HaystackDictionary dict, string name) 49 | { 50 | return dict.Get(name).Value; 51 | } 52 | 53 | public static double GetDoubleUnchecked(this HaystackDictionary dict, string name) 54 | { 55 | return dict.GetNullableDouble(name) ?? 0; 56 | } 57 | 58 | public static double? GetNullableDouble(this HaystackDictionary dict, string name) 59 | { 60 | return dict.GetUnchecked(name)?.Value; 61 | } 62 | 63 | public static int GetInt(this HaystackDictionary dict, string name) 64 | { 65 | return (int)dict.Get(name).Value; 66 | } 67 | 68 | public static int GetIntUnchecked(this HaystackDictionary dict, string name) 69 | { 70 | return dict.GetNullableInt(name) ?? 0; 71 | } 72 | 73 | public static int? GetNullableInt(this HaystackDictionary dict, string name) 74 | { 75 | return (int?)dict.GetUnchecked(name)?.Value; 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /ProjectHaystack/Extensions/IHaystackClientExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | 4 | namespace ProjectHaystack.Client 5 | { 6 | public static class IHaystackClientExtensions 7 | { 8 | /// 9 | /// Convenience method to call HisWriteNoWarnAsync with a "noWarn" marker to 10 | /// prevent warnings when writing out-of-order data. 11 | /// Record ID. 12 | /// Time-series data. 13 | public static Task HisWriteNoWarnAsync(this IHaystackClient client, HaystackReference id, HaystackHistoryItem[] items) 14 | => HisWriteNoWarnAsync(client, id, items, CancellationToken.None); 15 | 16 | /// 17 | /// Convenience method to call HisWriteNoWarnAsync with a "noWarn" marker to 18 | /// prevent warnings when writing out-of-order data. 19 | /// Record ID. 20 | /// Time-series data. 21 | public static Task HisWriteNoWarnAsync(this IHaystackClient client, HaystackReference id, HaystackHistoryItem[] items, CancellationToken cancellationToken) 22 | { 23 | var meta = new HaystackDictionary(); 24 | meta.Add("noWarn", new HaystackMarker()); 25 | return client.HisWriteAsync(id, items, cancellationToken, meta); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /ProjectHaystack/Extensions/UriExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProjectHaystack.Util 4 | { 5 | public static class UriExtensions 6 | { 7 | /// 8 | /// Ensure a URI ending with a slash. 9 | /// 10 | public static Uri EndWithSlash(this Uri uri) 11 | { 12 | if (uri.AbsolutePath.EndsWith("/")) 13 | { 14 | return uri; 15 | } 16 | 17 | var builder = new UriBuilder(uri); 18 | builder.Path += "/"; 19 | return builder.Uri; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /ProjectHaystack/OSS_TimeZoneConverter.txt: -------------------------------------------------------------------------------- 1 | TimeZoneConverter 2 | Copyright (c) 2017 Matt Johnson 3 | https://github.com/mj1856/TimeZoneConverter 4 | 5 | While we certainly hope this software is useful, none of the authors or 6 | contributors place any guarantees as to the accuracy of the data or the 7 | results returned by using this library. 8 | 9 | This library is distributed under the terms of the MIT License: 10 | 11 | ----------------------------------------------------------------------------- 12 | The MIT License (MIT) 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy of 15 | this software and associated documentation files (the "Software"), to deal in 16 | the Software without restriction, including without limitation the rights to 17 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 18 | the Software, and to permit persons to whom the Software is furnished to do so, 19 | subject to the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included in all 22 | copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 26 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 27 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 28 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | ----------------------------------------------------------------------------- -------------------------------------------------------------------------------- /ProjectHaystack/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using ProjectHaystack.Client; 5 | 6 | namespace ProjectHaystack 7 | { 8 | public static class Program 9 | { 10 | public static void Main(string[] args) 11 | { 12 | if (args.Length != 3) 13 | { 14 | Console.WriteLine("usage: HClient "); 15 | Environment.Exit(0); 16 | } 17 | 18 | RunAsync(args[0], args[1], args[2]).Wait(); 19 | } 20 | 21 | public static async Task RunAsync(string uri, string user, string pass) 22 | { 23 | var client = new HaystackClient(user, pass, new Uri(uri)); 24 | await client.OpenAsync(); 25 | Console.WriteLine(await client.GetStringAsync("about", new Dictionary(), "text/zinc")); 26 | Console.ReadKey(); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /ProjectHaystack/ProjectHaystack.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0;net6.0;net5.0;netstandard2.1;netstandard2.0 5 | 2.0.0 6 | SkyFoundry and Project Haystack Community 7 | SkyFoundry 8 | 9 | A library for working with the Project Haystack data model for semantic tagging of data. Includes a client for invoking Haystack Ops on compliant servers. 10 | 2017 11 | ProjectHaystack.Client 12 | true 13 | ProjectHaystack.Client 14 | true 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /ProjectHaystack/ProjectHaystack.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $id$ 5 | $version$ 6 | $title$ 7 | $authors$ 8 | $author$ 9 | AFL-3.0 10 | https://github.com/Strukton-Worksphere/haystack-csharp 11 | false 12 | $description$ 13 | 14 | Copyright 2017 15 | haystack SCRAM client SkySpark 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /ProjectHaystack/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:52378/", 7 | "sslPort": 44390 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "ProjectHaystack": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "environmentVariables": { 22 | "ASPNETCORE_ENVIRONMENT": "Development" 23 | }, 24 | "applicationUrl": "https://localhost:5001;http://localhost:5000" 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackBinary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.Validation; 3 | 4 | namespace ProjectHaystack 5 | { 6 | /// 7 | /// Binary data with mime type. 8 | /// 9 | public class HaystackBinary : HaystackValue 10 | { 11 | public string Mime { get; } 12 | 13 | public HaystackBinary(string mimeType) 14 | { 15 | Mime = HaystackValidator.IsMimeType(mimeType) 16 | ? mimeType 17 | : throw new ArgumentException($"Invalid mime type: {mimeType}", "mimeType"); 18 | } 19 | 20 | public override int GetHashCode() => Mime.GetHashCode(); 21 | 22 | public override bool Equals(object other) => other != null && other is HaystackBinary bin && Mime.Equals(bin.Mime); 23 | } 24 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackBoolean.cs: -------------------------------------------------------------------------------- 1 | namespace ProjectHaystack 2 | { 3 | /// 4 | /// Boolean value. 5 | /// 6 | public class HaystackBoolean : HaystackValue 7 | { 8 | private static readonly HaystackBoolean _true = new HaystackBoolean(true); 9 | private static readonly HaystackBoolean _false = new HaystackBoolean(false); 10 | 11 | public HaystackBoolean(bool value) 12 | { 13 | Value = value; 14 | } 15 | 16 | public static HaystackBoolean True => _true; 17 | public static HaystackBoolean False => _false; 18 | 19 | public bool Value { get; } 20 | 21 | public override int GetHashCode() => Value.GetHashCode(); 22 | 23 | public override bool Equals(object other) => other != null && other is HaystackBoolean boolean && boolean.Value == Value; 24 | } 25 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackCaretSymbol.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.Validation; 3 | 4 | namespace ProjectHaystack 5 | { 6 | public class HaystackCaretSymbol : HaystackValue 7 | { 8 | public HaystackCaretSymbol(string value) 9 | { 10 | Value = value == null || HaystackValidator.IsReferenceId(value) 11 | ? value 12 | : throw new ArgumentException($"Invalid id val: {value}", "value"); 13 | } 14 | 15 | public string Value { get; } 16 | public string Code => "^" + Value; 17 | 18 | public override int GetHashCode() => Value.GetHashCode(); 19 | 20 | public override bool Equals(object other) => other != null && other is HaystackCaretSymbol caretSymbol && (caretSymbol.Value?.Equals(Value) ?? false); 21 | } 22 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackColumn.cs: -------------------------------------------------------------------------------- 1 | namespace ProjectHaystack 2 | { 3 | /// 4 | /// Haystack column information. 5 | /// 6 | public class HaystackColumn 7 | { 8 | public HaystackColumn(int index, string name, HaystackDictionary meta = null) 9 | { 10 | Index = index; 11 | Name = name; 12 | Meta = meta ?? new HaystackDictionary(); 13 | } 14 | 15 | public int Index { get; } 16 | public string Name { get; } 17 | public HaystackDictionary Meta { get; } 18 | 19 | public string Display 20 | { 21 | get 22 | { 23 | HaystackValue dis = Meta.ContainsKey("dis") ? Meta["dis"] : null; 24 | return dis is HaystackString str ? str.Value : Name; 25 | } 26 | } 27 | 28 | public override int GetHashCode() => Name.GetHashCode() ^ Meta.GetHashCode(); 29 | 30 | public override bool Equals(object other) => other != null && other is HaystackColumn col && Name.Equals(col.Name) && Meta.Equals(col.Meta); 31 | } 32 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackCoordinate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.Validation; 3 | 4 | namespace ProjectHaystack 5 | { 6 | /// 7 | /// Haystack world coordinate. 8 | /// 9 | public class HaystackCoordinate : HaystackValue 10 | { 11 | public HaystackCoordinate(decimal latitude, decimal longitude) 12 | { 13 | if (!HaystackValidator.IsLatitude(latitude)) throw new ArgumentException("Invalid latitude > +/- 90", "latitude"); 14 | if (!HaystackValidator.IsLongitude(longitude)) throw new ArgumentException("Invalid longitude > +/- 180", "longitude"); 15 | 16 | Latitude = latitude; 17 | Longitude = longitude; 18 | } 19 | 20 | public decimal Latitude { get; set; } 21 | 22 | public decimal Longitude { get; set; } 23 | 24 | public override int GetHashCode() => Latitude.GetHashCode() ^ Longitude.GetHashCode(); 25 | 26 | public override bool Equals(object other) 27 | { 28 | return other != null 29 | && other is HaystackCoordinate coordinate 30 | && Latitude == coordinate.Latitude 31 | && Longitude == coordinate.Longitude; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackDate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProjectHaystack 4 | { 5 | /// 6 | /// Haystack date value. 7 | /// 8 | public class HaystackDate : HaystackValue, IComparable 9 | { 10 | public HaystackDate(DateTime date) 11 | { 12 | Value = date.Date; 13 | } 14 | 15 | public HaystackDate(int year, int month, int day) 16 | { 17 | Value = new DateTime(year, month, day); 18 | } 19 | 20 | public DateTime Value { get; } 21 | 22 | public static HaystackDate Today => new HaystackDate(DateTime.Today); 23 | 24 | public override int GetHashCode() => Value.GetHashCode(); 25 | 26 | public override bool Equals(object other) => other != null && other is HaystackDate date && date.Value == Value; 27 | 28 | public int CompareTo(object obj) 29 | { 30 | #if NETSTANDARD2_0 || NETSTANDARD2_1 31 | if (obj == null || !(obj is HaystackDate date)) 32 | { 33 | return 1; 34 | } 35 | #else 36 | if (obj == null || obj is not HaystackDate date) 37 | { 38 | return 1; 39 | } 40 | #endif 41 | 42 | return Value.CompareTo(date.Value); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackDateTime.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProjectHaystack 4 | { 5 | /// 6 | /// Haystack date and time value including timezone. 7 | /// 8 | public class HaystackDateTime : HaystackValue 9 | { 10 | public HaystackDateTime(DateTimeOffset dateTime, HaystackTimeZone timeZone) 11 | { 12 | Value = dateTime; 13 | TimeZone = timeZone; 14 | } 15 | 16 | public HaystackDateTime(DateTime dateTime, HaystackTimeZone timeZone) 17 | { 18 | Value = new DateTimeOffset(dateTime.Ticks, timeZone.TimeZoneInfo.GetUtcOffset(dateTime)); 19 | TimeZone = timeZone; 20 | } 21 | 22 | public HaystackDateTime(HaystackDate date, HaystackTime time, HaystackTimeZone timeZone) 23 | : this(date.Value + time.Value, timeZone) 24 | { 25 | } 26 | 27 | public DateTimeOffset Value { get; private set; } 28 | 29 | public HaystackTimeZone TimeZone { get; private set; } 30 | 31 | public static HaystackDateTime Now(HaystackTimeZone tz) => new HaystackDateTime(System.DateTime.Now, tz); 32 | 33 | public static HaystackDateTime Now() => new HaystackDateTime(System.DateTime.Now, HaystackTimeZone.UTC); 34 | 35 | public override int GetHashCode() => Value.GetHashCode() ^ TimeZone.GetHashCode(); 36 | 37 | public override bool Equals(object other) 38 | { 39 | return other != null 40 | && other is HaystackDateTime dateTime 41 | && dateTime.Value.Equals(Value) 42 | && dateTime.TimeZone.Equals(TimeZone); 43 | } 44 | 45 | public int CompareTo(HaystackDateTime other) => Value.ToUniversalTime().CompareTo(other.Value.ToUniversalTime()); 46 | } 47 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackDateTimeRange.cs: -------------------------------------------------------------------------------- 1 | namespace ProjectHaystack 2 | { 3 | /// 4 | /// Haystack date and time range. 5 | /// Inclusive start, exclusive end. 6 | /// 7 | public class HaystackDateTimeRange 8 | { 9 | public HaystackDateTimeRange(HaystackDateTime start, HaystackDateTime end) 10 | { 11 | Start = start; 12 | End = end; 13 | } 14 | 15 | public HaystackDateTime Start { get; } 16 | public HaystackDateTime End { get; } 17 | } 18 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackDefinition.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.Validation; 3 | 4 | namespace ProjectHaystack 5 | { 6 | public class HaystackDefinition : HaystackValue 7 | { 8 | public HaystackDefinition(string value) 9 | { 10 | Value = value != null && value.StartsWith("^") && HaystackValidator.IsTagName(value) 11 | ? value 12 | : throw new ArgumentException($"Invalid definition value: {value}"); 13 | } 14 | 15 | public string Value { get; } 16 | 17 | public override int GetHashCode() => Value.GetHashCode(); 18 | 19 | public override bool Equals(object other) => other != null && other is HaystackDefinition def && Value.Equals(def.Value); 20 | } 21 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackHistoryItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace ProjectHaystack 6 | { 7 | /// 8 | /// Haystack history item containing a timestamp and a value. 9 | /// 10 | public class HaystackHistoryItem : HaystackValue 11 | { 12 | public HaystackHistoryItem(HaystackDateTime timeStamp, HaystackValue Value) 13 | { 14 | TimeStamp = timeStamp ?? throw new ArgumentNullException(nameof(timeStamp)); 15 | this.Value = Value ?? throw new ArgumentNullException(nameof(Value)); 16 | } 17 | 18 | public HaystackHistoryItem(HaystackDictionary dictionary) 19 | { 20 | if (dictionary is null) 21 | { 22 | throw new ArgumentNullException(nameof(dictionary)); 23 | } 24 | 25 | TimeStamp = (HaystackDateTime)dictionary["ts"]; 26 | Value = dictionary.ContainsKey("val") ? dictionary["val"] : null; 27 | } 28 | 29 | public HaystackDateTime TimeStamp { get; } 30 | 31 | public HaystackValue Value { get; } 32 | 33 | /// 34 | /// Read a grid of "ts" and "val" data. 35 | /// 36 | /// Grid to read. 37 | /// List of history items. 38 | public static IEnumerable ReadGrid(HaystackGrid grid) 39 | { 40 | var ts = grid.Column("ts"); 41 | var val = grid.Column("val"); 42 | return grid.Rows 43 | .Select(row => new HaystackHistoryItem(row)); 44 | } 45 | 46 | public override int GetHashCode() => TimeStamp.GetHashCode(); 47 | 48 | public override bool Equals(object other) 49 | { 50 | return other != null 51 | && other is HaystackHistoryItem historyItem 52 | && historyItem.TimeStamp.Equals(TimeStamp) 53 | && historyItem.Value.Equals(Value); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackList.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace ProjectHaystack 6 | { 7 | /// 8 | /// List of Haystack values. 9 | /// 10 | public class HaystackList : HaystackValue, IList 11 | { 12 | private readonly List _list; 13 | 14 | public HaystackList(List list) 15 | { 16 | _list = list; 17 | } 18 | 19 | public HaystackList(params HaystackValue[] list) 20 | { 21 | _list = list.ToList(); 22 | } 23 | 24 | public int Count => _list.Count; 25 | 26 | public bool IsReadOnly => false; 27 | 28 | public HaystackValue this[int index] { get => _list[index]; set => _list[index] = value; } 29 | 30 | public override int GetHashCode() => _list.GetHashCode(); 31 | 32 | public override bool Equals(object other) 33 | { 34 | return other != null 35 | && other is HaystackList list 36 | && list._list.Count == _list.Count 37 | && Enumerable.Range(0, list._list.Count).All(idx => list._list[idx].Equals(_list[idx])); 38 | } 39 | 40 | public int IndexOf(HaystackValue item) => _list.IndexOf(item); 41 | 42 | public void Insert(int index, HaystackValue item) => _list.Insert(index, item); 43 | 44 | public void RemoveAt(int index) => _list.RemoveAt(index); 45 | 46 | public void Add(HaystackValue item) => _list.Add(item); 47 | 48 | public void Clear() => _list.Clear(); 49 | 50 | public bool Contains(HaystackValue item) => _list.Contains(item); 51 | 52 | public void CopyTo(HaystackValue[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex); 53 | 54 | public bool Remove(HaystackValue item) => _list.Remove(item); 55 | 56 | public IEnumerator GetEnumerator() => _list.GetEnumerator(); 57 | 58 | IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); 59 | } 60 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackMarker.cs: -------------------------------------------------------------------------------- 1 | namespace ProjectHaystack 2 | { 3 | /// 4 | /// Haystack marker value. 5 | /// 6 | public class HaystackMarker : HaystackValue 7 | { 8 | public static readonly HaystackMarker Instance = new HaystackMarker(); 9 | 10 | public override int GetHashCode() { return 0; } 11 | 12 | public override bool Equals(object other) => other != null && other is HaystackMarker; 13 | } 14 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackNotAvailable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProjectHaystack 4 | { 5 | /// 6 | /// Haystack not available (NA) marker value. 7 | /// 8 | public class HaystackNotAvailable : HaystackValue 9 | { 10 | public static HaystackNotAvailable Instance = new HaystackNotAvailable(); 11 | 12 | public override int GetHashCode() => 0; 13 | 14 | public override bool Equals(object other) => other != null && other is HaystackNotAvailable; 15 | 16 | public override string ToString() 17 | { 18 | throw new NotImplementedException("ToString is not implemented to prevent inconsistent results."); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackNumber.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.Validation; 3 | 4 | namespace ProjectHaystack 5 | { 6 | /// 7 | /// Haystack number with optional unit. 8 | /// 9 | public class HaystackNumber : HaystackValue 10 | { 11 | public HaystackNumber(double value, string unit = null) 12 | { 13 | if (!HaystackValidator.IsUnitName(unit)) 14 | { 15 | throw new ArgumentException($"Invalid unit name: {unit}", nameof(unit)); 16 | } 17 | 18 | Value = value; 19 | Unit = unit; 20 | } 21 | 22 | public double Value { get; } 23 | public string Unit { get; } 24 | 25 | public static HaystackNumber ZERO = new HaystackNumber(0.0, null); 26 | public static HaystackNumber POS_INF = new HaystackNumber(double.PositiveInfinity, null); 27 | public static HaystackNumber NEG_INF = new HaystackNumber(double.NegativeInfinity, null); 28 | public static HaystackNumber NaN = new HaystackNumber(double.NaN, null); 29 | 30 | public override int GetHashCode() 31 | { 32 | var unsigned = Convert.ToUInt64(BitConverter.DoubleToInt64Bits(Value)); 33 | int hash = (int)(unsigned ^ (unsigned >> 32)); 34 | if (Unit != null) 35 | hash ^= Unit.GetHashCode(); 36 | return hash; 37 | } 38 | 39 | public override bool Equals(object other) => other != null && other is HaystackNumber number && number.Value.Equals(Value) && number.Unit == Unit; 40 | 41 | public int CompareTo(object other) 42 | { 43 | #if NETSTANDARD2_0 || NETSTANDARD2_1 44 | if (other == null || !(other is HaystackNumber number)) 45 | { 46 | return 1; 47 | } 48 | #else 49 | if (other == null || other is not HaystackNumber number) 50 | { 51 | return 1; 52 | } 53 | #endif 54 | 55 | return Value.CompareTo(number.Value); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackReference.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.Validation; 3 | 4 | namespace ProjectHaystack 5 | { 6 | public class HaystackReference : HaystackValue 7 | { 8 | public HaystackReference(string value, string dis = null) 9 | { 10 | Value = value == null || HaystackValidator.IsReferenceId(value) 11 | ? value 12 | : throw new ArgumentException($"Invalid id val: {value}", "value"); 13 | Display = dis; 14 | } 15 | 16 | public static HaystackReference nullRef = new HaystackReference(null, null); 17 | 18 | public string Value { get; } 19 | public string Display { get; } 20 | public string Code => "@" + Value; 21 | 22 | public override int GetHashCode() => Value.GetHashCode(); 23 | 24 | public override bool Equals(object other) => other != null && other is HaystackReference reference && (reference.Value?.Equals(Value) ?? false); 25 | } 26 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackRemove.cs: -------------------------------------------------------------------------------- 1 | namespace ProjectHaystack 2 | { 3 | /// 4 | /// Haystack remove marker value. 5 | /// 6 | public class HaystackRemove : HaystackValue 7 | { 8 | public static HaystackRemove Instance = new HaystackRemove(); 9 | 10 | public override int GetHashCode() { return 0; } 11 | 12 | public override bool Equals(object other) => other != null && other is HaystackRemove; 13 | } 14 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackRow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace ProjectHaystack 6 | { 7 | /// 8 | /// Row in a Haystack grid. 9 | /// 10 | public class HaystackRow : HaystackDictionary 11 | { 12 | public HaystackRow(HaystackGrid grid, params HaystackValue[] values) 13 | : base(new Lazy>(() => ToDictionary(grid, values))) 14 | { 15 | Grid = grid; 16 | } 17 | 18 | public HaystackGrid Grid { get; } 19 | 20 | public override ICollection Values => _source.Value.Values; 21 | 22 | public override void Add(string key, HaystackValue value) 23 | { 24 | throw new InvalidOperationException("Cannot add values to a row as it will affect the entire grid"); 25 | } 26 | 27 | public override bool Remove(string key) 28 | { 29 | throw new InvalidOperationException("Cannot remove values from a row as it will affect the entire grid"); 30 | } 31 | 32 | public HaystackValue this[int index] 33 | { 34 | get => Get(Grid.Column(index).Name); 35 | set 36 | { 37 | var key = Grid.Column(index).Name; 38 | _source.Value[key] = value; 39 | } 40 | } 41 | 42 | public override HaystackValue this[string key] 43 | { 44 | get => Get(key); 45 | set 46 | { 47 | if (!_source.Value.ContainsKey(key)) 48 | throw new HaystackUnknownNameException("Cannot add values to a row as it will affect the entire grid"); 49 | _source.Value[key] = value; 50 | } 51 | } 52 | 53 | private static IDictionary ToDictionary(HaystackGrid grid, HaystackValue[] values) 54 | { 55 | if (values == null || grid.ColumnCount != values.Length) 56 | { 57 | throw new ArgumentException($"Row count {values.Length} does not match col count {grid.ColumnCount}", "values"); 58 | } 59 | 60 | #if NETSTANDARD2_0 || NETSTANDARD2_1 61 | return grid.Columns 62 | .Select((col, idx) => new KeyValuePair(col.Name, values[idx])) 63 | .ToDictionary(kv => kv.Key, kv => kv.Value); 64 | #else 65 | return new Dictionary(grid.Columns 66 | .Select((col, idx) => new KeyValuePair(col.Name, values[idx]))); 67 | #endif 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackString.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProjectHaystack 4 | { 5 | public class HaystackString : HaystackValue, IComparable 6 | { 7 | private static HaystackString _empty = new HaystackString(string.Empty); 8 | 9 | public HaystackString(string value) 10 | { 11 | Value = value; 12 | } 13 | 14 | public static HaystackString Empty => _empty; 15 | 16 | public string Value { get; } 17 | 18 | public override int GetHashCode() => Value.GetHashCode(); 19 | 20 | public override bool Equals(object other) => other != null && other is HaystackString str && str.Value == Value; 21 | 22 | public int CompareTo(object obj) 23 | { 24 | #if NETSTANDARD2_0 || NETSTANDARD2_1 25 | if (obj != null && obj is HaystackString str) 26 | { 27 | return Value.CompareTo(str.Value); 28 | } 29 | return 1; 30 | #else 31 | if (obj == null || obj is not HaystackString str) 32 | { 33 | return 1; 34 | } 35 | return Value.CompareTo(str.Value); 36 | #endif 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackTime.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProjectHaystack 4 | { 5 | /// 6 | /// Haystack time of day value. 7 | /// 8 | public class HaystackTime : HaystackValue, IComparable 9 | { 10 | public HaystackTime(TimeSpan time) 11 | { 12 | Value = time; 13 | } 14 | 15 | public HaystackTime(int hours, int minutes, int seconds) 16 | : this(new TimeSpan(hours, minutes, seconds)) 17 | { 18 | } 19 | 20 | public TimeSpan Value { get; private set; } 21 | 22 | public override int GetHashCode() => Value.GetHashCode(); 23 | 24 | public override bool Equals(object other) => other != null && other is HaystackTime time && Value.Equals(time.Value); 25 | 26 | public int CompareTo(object obj) 27 | { 28 | #if NETSTANDARD2_0 || NETSTANDARD2_1 29 | if (obj == null || !(obj is HaystackTime time)) 30 | { 31 | return 1; 32 | } 33 | #else 34 | if (obj == null || obj is not HaystackTime time) 35 | { 36 | return 1; 37 | } 38 | #endif 39 | 40 | return Value.CompareTo(time.Value); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackTimeZone.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using TimeZoneConverter; 4 | 5 | namespace ProjectHaystack 6 | { 7 | /// 8 | /// Haystack time zone information. 9 | /// 10 | /// 11 | /// Handles mapping between Haystack timezone names and dotnet timezones. 12 | /// 13 | public class HaystackTimeZone 14 | { 15 | public HaystackTimeZone(string name, TimeZoneInfo timeZoneInfo) 16 | { 17 | Name = name; 18 | TimeZoneInfo = timeZoneInfo; 19 | } 20 | 21 | public HaystackTimeZone(string name) 22 | { 23 | Name = name; 24 | TimeZoneInfo = LocateTimeZoneByName(name); 25 | } 26 | 27 | public HaystackTimeZone(TimeZoneInfo timeZoneInfo) 28 | { 29 | TimeZoneInfo = timeZoneInfo; 30 | Name = LocateTimeZoneName(timeZoneInfo); 31 | } 32 | 33 | public string Name { get; } 34 | public TimeZoneInfo TimeZoneInfo { get; } 35 | 36 | public static HaystackTimeZone UTC => new HaystackTimeZone("UTC"); 37 | 38 | public static HaystackTimeZone REL => new HaystackTimeZone("Rel"); 39 | 40 | public static HaystackTimeZone Default => new HaystackTimeZone(TimeZoneInfo.Local.Id); 41 | 42 | public override int GetHashCode() => Name.GetHashCode(); 43 | 44 | public override bool Equals(object other) => other != null && other is HaystackTimeZone timeZone && timeZone.Name.Equals(Name); 45 | 46 | private static TimeZoneInfo LocateTimeZoneByName(string name) 47 | { 48 | if (string.IsNullOrWhiteSpace(name)) 49 | { 50 | throw new ArgumentException("Value must not be empty", nameof(name)); 51 | } 52 | 53 | string nameToSearch = name?.ToUpper().Trim(); 54 | 55 | // For "Rel" timezone, use "GMT" 56 | if (nameToSearch == "REL") 57 | { 58 | nameToSearch = "GMT"; 59 | } 60 | 61 | TimeZoneInfo tziFound = null; 62 | var bestMatch = TZConvert.KnownIanaTimeZoneNames 63 | .Where(tzName => tzName.ToUpper().Contains(nameToSearch)) 64 | .OrderBy(tzName => tzName.Length) 65 | .FirstOrDefault(); 66 | if (bestMatch == null) 67 | { 68 | throw new ArgumentException($"Could not find IANA timezone with name {name}", nameof(name)); 69 | } 70 | if (!TZConvert.TryGetTimeZoneInfo(bestMatch, out tziFound)) 71 | { 72 | throw new ArgumentException($"An exception occurred when trying to convert from IANA to Windows Time Zone for value {tziFound}", nameof(name)); 73 | } 74 | return tziFound; 75 | } 76 | 77 | private static string LocateTimeZoneName(TimeZoneInfo dntzi) 78 | { 79 | if (dntzi == null) 80 | { 81 | throw new ArgumentException("Value must not be empty", nameof(dntzi)); 82 | } 83 | 84 | if (!TZConvert.TryWindowsToIana(dntzi.Id, out var iana)) 85 | { 86 | if (!TZConvert.TryWindowsToIana(dntzi.Id.Replace("Etc/", ""), out iana)) 87 | { 88 | throw new ArgumentException($"Windows time zone id {dntzi.Id} could not be converted to IANA tz id", nameof(dntzi)); 89 | } 90 | } 91 | 92 | var nameToSearch = iana.ToUpper(); 93 | var bestMatch = HaystackTimeZoneDatabase.TimeZones 94 | .Where(tzName => nameToSearch.Contains(tzName.ToUpper())) 95 | .OrderByDescending(tzName => tzName.Length) 96 | .FirstOrDefault(); 97 | if (bestMatch == null) 98 | { 99 | throw new ArgumentException($"Windows time zone id {dntzi.Id} converted to IANA id {iana} could not be found in known Haystack ids", nameof(dntzi)); 100 | } 101 | return bestMatch; 102 | } 103 | } 104 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackUri.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProjectHaystack 4 | { 5 | /// 6 | /// Haystack URI value. 7 | /// 8 | public class HaystackUri : HaystackValue 9 | { 10 | public HaystackUri(string value) 11 | { 12 | Value = value ?? throw new ArgumentException("Uri cannot be null", nameof(value)); 13 | } 14 | 15 | public string Value { get; } 16 | 17 | // Hash code is based on string value 18 | public override int GetHashCode() => Value.GetHashCode(); 19 | 20 | // Equals is based on string value 21 | public override bool Equals(object other) => other != null && other is HaystackUri uri && uri.Value.Equals(Value); 22 | } 23 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackValue.cs: -------------------------------------------------------------------------------- 1 | namespace ProjectHaystack 2 | { 3 | /// 4 | /// Base class for Haystack values. 5 | /// 6 | public abstract class HaystackValue 7 | { 8 | public abstract override bool Equals(object other); 9 | public abstract override int GetHashCode(); 10 | 11 | public static bool operator ==(HaystackValue left, HaystackValue right) => Equals(left, null) ? Equals(right, null) : left.Equals(right); 12 | public static bool operator !=(HaystackValue left, HaystackValue right) => !(left == right); 13 | } 14 | } -------------------------------------------------------------------------------- /ProjectHaystack/Values/HaystackXString.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ProjectHaystack.Validation; 3 | 4 | namespace ProjectHaystack 5 | { 6 | /// 7 | /// Haystack extended string containing a type and value encoded as a string. 8 | /// It is used as a generic value when no predefined type is used. 9 | /// 10 | public class HaystackXString : HaystackValue 11 | { 12 | public HaystackXString(string value, string type = null) 13 | { 14 | Value = value; 15 | Type = HaystackValidator.IsTypeName(type) 16 | ? type 17 | : throw new ArgumentException($"Invalid type name: {type}", nameof(type)); 18 | } 19 | 20 | public string Value { get; } 21 | 22 | public string Type { get; } 23 | 24 | public override int GetHashCode() => Type.GetHashCode() * 31 + Value.GetHashCode(); 25 | 26 | public override bool Equals(object other) => other != null && other is HaystackXString xstr && xstr.Value == Value && xstr.Type == Type; 27 | } 28 | } -------------------------------------------------------------------------------- /ProjectHaystack/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /ProjectHaystack/io/HaystackToken.cs: -------------------------------------------------------------------------------- 1 | namespace ProjectHaystack.io 2 | { 3 | public class HaystackToken 4 | { 5 | public string Symbol { get; private set; } 6 | public bool Literal { get; private set; } 7 | 8 | public static HaystackToken eof = new HaystackToken("eof"); 9 | 10 | public static HaystackToken id = new HaystackToken("identifier"); 11 | public static HaystackToken num = new HaystackToken("Number", true); 12 | public static HaystackToken str = new HaystackToken("Str", true); 13 | public static HaystackToken @ref = new HaystackToken("Ref", true); 14 | public static HaystackToken caretSymbol = new HaystackToken("Symbol", true); 15 | public static HaystackToken uri = new HaystackToken("Uri", true); 16 | public static HaystackToken date = new HaystackToken("Date", true); 17 | public static HaystackToken time = new HaystackToken("Time", true); 18 | public static HaystackToken dateTime = new HaystackToken("DateTime", true); 19 | 20 | public static HaystackToken colon = new HaystackToken(":"); 21 | public static HaystackToken comma = new HaystackToken(","); 22 | public static HaystackToken semicolon = new HaystackToken(";"); 23 | public static HaystackToken minus = new HaystackToken("-"); 24 | public static HaystackToken eq = new HaystackToken("=="); 25 | public static HaystackToken notEq = new HaystackToken("!="); 26 | public static HaystackToken lt = new HaystackToken("<"); 27 | public static HaystackToken lt2 = new HaystackToken("<<"); 28 | public static HaystackToken ltEq = new HaystackToken("<="); 29 | public static HaystackToken gt = new HaystackToken(">"); 30 | public static HaystackToken gt2 = new HaystackToken(">>"); 31 | public static HaystackToken gtEq = new HaystackToken(">="); 32 | public static HaystackToken lbracket = new HaystackToken("["); 33 | public static HaystackToken rbracket = new HaystackToken("]"); 34 | public static HaystackToken lbrace = new HaystackToken("{"); 35 | public static HaystackToken rbrace = new HaystackToken("}"); 36 | public static HaystackToken lparen = new HaystackToken("("); 37 | public static HaystackToken rparen = new HaystackToken(")"); 38 | public static HaystackToken arrow = new HaystackToken("->"); 39 | public static HaystackToken slash = new HaystackToken("/"); 40 | public static HaystackToken assign = new HaystackToken("="); 41 | public static HaystackToken bang = new HaystackToken("!"); 42 | public static HaystackToken nl = new HaystackToken("newline"); 43 | 44 | public HaystackToken(string symbol) 45 | { 46 | Symbol = symbol; 47 | Literal = false; 48 | } 49 | 50 | public HaystackToken(string symbol, bool literal) 51 | { 52 | Symbol = symbol; 53 | Literal = literal; 54 | } 55 | 56 | public override bool Equals(object o) 57 | { 58 | if (this == o) return true; // reference check 59 | if (o == null || (!(o is HaystackToken))) return false; // null and type check 60 | 61 | HaystackToken that = (HaystackToken)o; 62 | // Value compare 63 | if (Literal != that.Literal) return false; 64 | return (Symbol.CompareTo(that.Symbol) == 0); 65 | } 66 | 67 | public override int GetHashCode() 68 | { 69 | int result = Symbol.GetHashCode(); 70 | result = 31 * result + (Literal ? 1 : 0); 71 | return result; 72 | } 73 | 74 | public override string ToString() 75 | { 76 | return Symbol; 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /ProjectHaystack/io/TrioWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text.RegularExpressions; 4 | 5 | namespace ProjectHaystack.io 6 | { 7 | public class TrioWriter : IDisposable 8 | { 9 | // Strings can be left unquoted if they begin with any of these "safe" chars: 10 | // Any non-ASCII Unicode character, A-Z, a-z, underbar, dash, or space. 11 | private Regex _safeCharsRegex = new Regex(@"^[^\x00-\x7F]|^[A-Za-z0-9_\ ]+$", RegexOptions.Compiled); 12 | private readonly TextWriter _trioWriter; 13 | private bool isFirst = true; 14 | 15 | public TrioWriter(TextWriter writer) 16 | { 17 | _trioWriter = writer; 18 | } 19 | 20 | public TrioWriter(Stream trioStream) 21 | { 22 | _trioWriter = new StreamWriter(trioStream, null, 1024, true); 23 | } 24 | 25 | public void WriteGrid(HaystackGrid grid) 26 | { 27 | foreach (var row in grid.Rows) 28 | WriteEntity(row); 29 | } 30 | 31 | 32 | public void WriteEntity(HaystackDictionary entity) 33 | { 34 | if (isFirst) 35 | isFirst = false; 36 | else 37 | _trioWriter.WriteLine("---"); 38 | 39 | foreach (var kv in entity) 40 | { 41 | if (kv.Value == null) 42 | continue; 43 | _trioWriter.Write(kv.Key); 44 | if (kv.Value is HaystackMarker) 45 | { 46 | _trioWriter.WriteLine(); 47 | continue; 48 | } 49 | _trioWriter.Write(":"); 50 | if (kv.Value is HaystackGrid) 51 | { 52 | _trioWriter.Write("Zinc:"); 53 | _trioWriter.WriteLine(); 54 | var val = ZincWriter.ToZinc(kv.Value); 55 | foreach (var line in val.TrimEnd().Split(new[] { "\n" }, StringSplitOptions.None)) 56 | { 57 | _trioWriter.Write(" "); 58 | _trioWriter.WriteLine(line.TrimEnd()); 59 | } 60 | } 61 | else if (kv.Value is HaystackString stringValue && stringValue.Value.Contains("\n")) 62 | { 63 | var val = stringValue.Value; 64 | _trioWriter.WriteLine(); 65 | foreach (var line in val.TrimEnd().Split(new[] { "\n" }, StringSplitOptions.None)) 66 | { 67 | _trioWriter.Write(" "); 68 | _trioWriter.WriteLine(line.TrimEnd()); 69 | } 70 | } 71 | else 72 | { 73 | var val = ZincWriter.ToZinc(kv.Value); 74 | if (val.Contains("\\n")) 75 | val = val.Replace("\\n", "\n"); 76 | if (val.StartsWith("\"") && val.EndsWith("\"") && _safeCharsRegex.IsMatch(val.Substring(1, val.Length - 2))) 77 | val = val.Substring(1, val.Length - 2); 78 | _trioWriter.WriteLine(val.TrimEnd()); 79 | } 80 | } 81 | } 82 | 83 | public void WriteComment(string comment) 84 | { 85 | foreach (var line in comment.Split(new[] { "\n" }, StringSplitOptions.None)) 86 | { 87 | _trioWriter.Write("// "); 88 | _trioWriter.WriteLine(line.TrimEnd()); 89 | } 90 | } 91 | 92 | public void Dispose() 93 | { 94 | _trioWriter.Dispose(); 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/Auth/Util/Base64Test.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace ProjectHaystackTest.Util 5 | { 6 | using Base64 = ProjectHaystack.Util.Base64; 7 | 8 | [TestClass] 9 | public class Base64Test 10 | { 11 | private static string RandomString() 12 | { 13 | Guid g = Guid.NewGuid(); 14 | string GuidString = Convert.ToBase64String(g.ToByteArray()); 15 | GuidString = GuidString.Replace("=", ""); 16 | GuidString = GuidString.Replace("+", ""); 17 | return GuidString; 18 | } 19 | 20 | [TestMethod] 21 | public void StandardEncodeDecode() 22 | { 23 | for (var i = 0; i < 1000; i++) 24 | { 25 | var s1 = RandomString(); 26 | var enc = Base64.STANDARD.Encode(s1); 27 | var s2 = Base64.STANDARD.Decode(enc); 28 | Assert.AreEqual(s1, s2); 29 | } 30 | } 31 | 32 | [TestMethod] 33 | public void StandardUtf8EncodeDecode() 34 | { 35 | for (int i = 0; i < 1000; i++) 36 | { 37 | var s1 = RandomString(); 38 | var enc = Base64.STANDARD.EncodeUtf8(s1); 39 | var s2 = Base64.STANDARD.decodeUTF8(enc); 40 | Assert.AreEqual(s1, s2); 41 | } 42 | } 43 | 44 | [TestMethod] 45 | public void UriEncodeDecode() 46 | { 47 | for (int i = 0; i < 1000; i++) 48 | { 49 | var s1 = RandomString(); 50 | var enc = Base64.URI.Encode(s1); 51 | var s2 = Base64.URI.Decode(enc); 52 | Assert.AreEqual(s1, s2); 53 | } 54 | } 55 | 56 | [TestMethod] 57 | public void UriUtf8EncodeDecode() 58 | { 59 | for (int i = 0; i < 1000; i++) 60 | { 61 | var s1 = RandomString(); 62 | var enc = Base64.URI.EncodeUtf8(s1); 63 | var s2 = Base64.URI.decodeUTF8(enc); 64 | Assert.AreEqual(s1, s2); 65 | } 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/Auth/Util/Pbkdf2Test.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security.Cryptography; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | 5 | namespace ProjectHaystackTest.Util 6 | { 7 | using Pbkdf2 = ProjectHaystack.Util.Pbkdf2; 8 | 9 | [TestClass] 10 | public class Pbkdf2Test 11 | { 12 | public void DoPbkTest(string password, string salt, int iterations, int dkLen, string expected) 13 | { 14 | using (var hmac = new HMACSHA256()) 15 | { 16 | var mine = new Pbkdf2(hmac, System.Text.Encoding.UTF8.GetBytes(password), System.Text.Encoding.UTF8.GetBytes(salt), iterations); 17 | var result = mine.GetBytes(dkLen); 18 | var usResult = (byte[])(Array)result; 19 | var hex = BitConverter.ToString(usResult); 20 | Assert.AreEqual(hex, expected); 21 | } 22 | } 23 | 24 | [TestMethod] 25 | public void PbkTest() 26 | { 27 | DoPbkTest("password", "salt", 1, 32, "12-0F-B6-CF-FC-F8-B3-2C-43-E7-22-52-56-C4-F8-37-A8-65-48-C9-2C-CC-35-48-08-05-98-7C-B7-0B-E1-7B"); 28 | DoPbkTest("password", "salt", 2, 32, "AE-4D-0C-95-AF-6B-46-D3-2D-0A-DF-F9-28-F0-6D-D0-2A-30-3F-8E-F3-C2-51-DF-D6-E2-D8-5A-95-47-4C-43"); 29 | DoPbkTest("password", "salt", 4096, 32, "C5-E4-78-D5-92-88-C8-41-AA-53-0D-B6-84-5C-4C-8D-96-28-93-A0-01-CE-4E-11-A4-96-38-73-AA-98-13-4A"); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HBinTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 3 | // Licensed under the Academic Free License version 3.0 4 | // 5 | // History: 6 | // 16 August 2018 Ian Davies Creation based on Java Toolkit at same time from project-haystack.org downloads 7 | // 8 | using Microsoft.VisualStudio.TestTools.UnitTesting; 9 | using ProjectHaystack; 10 | 11 | namespace ProjectHaystackTest 12 | { 13 | [TestClass] 14 | public class HBinTest : HValTest 15 | { 16 | [TestMethod] 17 | public void testEquality() 18 | { 19 | HBin bin1 = HBin.make("text/plain"); 20 | HBin bin2 = HBin.make("text/plain"); 21 | HBin bin3 = HBin.make("text/xml"); 22 | // Can't user AreEqual or AreNotEqual as these are objects and that is doing 23 | // a reference check not a logical value test because HBin does not implement 24 | // IComparable Interface - Haystack equals determines equality for this library purpose 25 | //e.g this will fail = Assert.AreEqual(HBin.make("text/plain"), HBin.make("text/plain")); 26 | Assert.IsTrue(bin1.hequals(bin2)); 27 | Assert.IsFalse(bin1.hequals(bin3)); 28 | } 29 | // TODO:FIXIT 30 | // // encoding 31 | // verifyZinc(HBin.make("text/plain"), "Bin(\"text/plain\")"); 32 | // verifyZinc(HBin.make("text/plain; charset=utf-8"), "Bin(\"text/plain; charset=utf-8\")"); 33 | // 34 | // // verify bad bins are caught on encoding 35 | // try { HBin.make("text/plain; f()").toZinc(); fail(); } catch (Exception e) { verifyException(e); } 36 | // try { read("Bin()"); fail(); } catch (Exception e) { verifyException(e); } 37 | // try { read("Bin(\"text\")"); fail(); } catch (Exception e) { verifyException(e); } 38 | } 39 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HBoolTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 3 | // Licensed under the Academic Free License version 3.0 4 | // 5 | // History: 6 | // 16 August 2018 Ian Davies Creation based on Java Toolkit at same time from project-haystack.org downloads 7 | // 8 | using Microsoft.VisualStudio.TestTools.UnitTesting; 9 | using ProjectHaystack; 10 | 11 | namespace ProjectHaystackTest 12 | { 13 | [TestClass] 14 | public class HBoolTest : HValTest 15 | { 16 | [TestMethod] 17 | public void testEquality() 18 | { 19 | Assert.IsTrue(HBool.TRUE.hequals(HBool.TRUE)); 20 | Assert.IsFalse(HBool.TRUE.hequals(HBool.FALSE)); 21 | Assert.IsTrue(HBool.make(true).hequals(HBool.TRUE)); 22 | Assert.IsTrue(HBool.make(false).hequals(HBool.FALSE)); 23 | } 24 | 25 | [TestMethod] 26 | public void testCompare() 27 | { 28 | Assert.IsTrue(HBool.FALSE.CompareTo(HBool.TRUE) < 0); 29 | Assert.AreEqual(HBool.TRUE.CompareTo(HBool.TRUE), 0); 30 | } 31 | 32 | [TestMethod] 33 | public void testZinc() 34 | { 35 | verifyZinc(HBool.TRUE, "T"); 36 | verifyZinc(HBool.FALSE, "F"); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HCoordTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 3 | // Licensed under the Academic Free License version 3.0 4 | // 5 | // History: 6 | // 16 August 2018 Ian Davies Creation based on Java Toolkit at same time from project-haystack.org downloads 7 | // 8 | using System; 9 | using Microsoft.VisualStudio.TestTools.UnitTesting; 10 | using ProjectHaystack; 11 | 12 | namespace ProjectHaystackTest 13 | { 14 | [TestClass] 15 | public class HCoordTest : HValTest 16 | { 17 | [TestMethod] 18 | public void testLatBoundaries() 19 | { 20 | verifyCoord(90, 123, "C(90,123)"); 21 | verifyCoord(-90, 123, "C(-90,123)"); 22 | verifyCoord(89.888999, 123, "C(89.888999,123)"); 23 | verifyCoord(-89.888999, 123, "C(-89.888999,123)"); 24 | } 25 | 26 | [TestMethod] 27 | public void testLonBoundaries() 28 | { 29 | verifyCoord(45, 180, "C(45,180)"); 30 | verifyCoord(45, -180, "C(45,-180)"); 31 | verifyCoord(45, 179.999129, "C(45,179.999129)"); 32 | verifyCoord(45, -179.999129, "C(45,-179.999129)"); 33 | } 34 | 35 | [TestMethod] 36 | public void testDecimalPlaces() 37 | { 38 | verifyCoord(9.1, -8.1, "C(9.1,-8.1)"); 39 | verifyCoord(9.12, -8.13, "C(9.12,-8.13)"); 40 | verifyCoord(9.123, -8.134, "C(9.123,-8.134)"); 41 | verifyCoord(9.1234, -8.1346, "C(9.1234,-8.1346)"); 42 | verifyCoord(9.12345, -8.13456, "C(9.12345,-8.13456)"); 43 | verifyCoord(9.123452, -8.134567, "C(9.123452,-8.134567)"); 44 | } 45 | 46 | [TestMethod] 47 | public void testZeroBoundaries() 48 | { 49 | verifyCoord(0, 0, "C(0,0)"); 50 | verifyCoord(0.3, -0.3, "C(0.3,-0.3)"); 51 | verifyCoord(0.03, -0.03, "C(0.03,-0.03)"); 52 | verifyCoord(0.003, -0.003, "C(0.003,-0.003)"); 53 | verifyCoord(0.0003, -0.0003, "C(0.0003,-0.0003)"); 54 | verifyCoord(0.02003, -0.02003, "C(0.02003,-0.02003)"); 55 | verifyCoord(0.020003, -0.020003, "C(0.020003,-0.020003)"); 56 | verifyCoord(0.000123, -0.000123, "C(0.000123,-0.000123)"); 57 | verifyCoord(7.000123, -7.000123, "C(7.000123,-7.000123)"); 58 | } 59 | 60 | [TestMethod] 61 | public void testIsLat() 62 | { 63 | Assert.IsFalse(HCoord.isLat(-91.0)); 64 | Assert.IsTrue(HCoord.isLat(-90.0)); 65 | Assert.IsTrue(HCoord.isLat(-89.0)); 66 | Assert.IsTrue(HCoord.isLat(90.0)); 67 | Assert.IsFalse(HCoord.isLat(91.0)); 68 | } 69 | 70 | [TestMethod] 71 | public void testIsLng() 72 | { 73 | Assert.IsFalse(HCoord.isLng(-181.0)); 74 | Assert.IsTrue(HCoord.isLng(-179.99)); 75 | Assert.IsTrue(HCoord.isLng(180.0)); 76 | Assert.IsFalse(HCoord.isLng(181.0)); 77 | } 78 | 79 | [TestMethod] 80 | public void testMakeErrors() 81 | { 82 | try { HCoord.make(91, 12); Assert.Fail(); } catch (ArgumentException) { Assert.IsTrue(true); } 83 | try { HCoord.make(-90.2, 12); Assert.Fail(); } catch (ArgumentException) { Assert.IsTrue(true); } 84 | try { HCoord.make(13, 180.009); Assert.Fail(); } catch (ArgumentException) { Assert.IsTrue(true); } 85 | try { HCoord.make(13, -181); Assert.Fail(); } catch (ArgumentException) { Assert.IsTrue(true); } 86 | } 87 | 88 | private void verifyCoord(double lat, double lng, string s) 89 | { 90 | HCoord c = HCoord.make(lat, lng); 91 | Assert.AreEqual(c.lat, lat); 92 | Assert.AreEqual(c.lng, lng); 93 | Assert.AreEqual(c.ToString(), s); 94 | HCoord strCoord = HCoord.make(s); 95 | Assert.IsTrue(strCoord.hequals(c)); 96 | } 97 | 98 | [TestMethod] 99 | [ExpectedException(typeof(FormatException))] // In Java this was parse exception 100 | public void RunBadZincProviderTest () 101 | { 102 | string[] badZincs = 103 | { "C(0.123,-.789)", 104 | "1,2", 105 | "(1,2)", 106 | "C(1,2", 107 | "C1,2)", 108 | "C(x,9)" }; 109 | foreach (string strCurZinc in badZincs) 110 | HCoord.make(strCurZinc); 111 | } 112 | 113 | } 114 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HDateTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 3 | // Licensed under the Academic Free License version 3.0 4 | // 5 | // History: 6 | // 16 August 2018 Ian Davies Creation based on Java Toolkit at same time from project-haystack.org downloads 7 | // 8 | using System; 9 | using Microsoft.VisualStudio.TestTools.UnitTesting; 10 | using ProjectHaystack; 11 | 12 | namespace ProjectHaystackTest 13 | { 14 | [TestClass] 15 | public class HDateTest : HValTest 16 | { 17 | [TestMethod] 18 | public void testEquality() 19 | { 20 | Assert.IsTrue(HDate.make(2011, 6, 7).hequals(HDate.make(2011, 6, 7))); 21 | Assert.IsFalse(HDate.make(2011, 6, 7).hequals(HDate.make(2011, 6, 8))); 22 | Assert.IsFalse(HDate.make(2011, 6, 7).hequals(HDate.make(2011, 2, 7))); 23 | Assert.IsFalse(HDate.make(2011, 6, 7).hequals(HDate.make(2009, 6, 7))); 24 | } 25 | 26 | [TestMethod] 27 | public void testCompare() 28 | { 29 | Assert.IsTrue(HDate.make(2011, 6, 9).CompareTo(HDate.make(2011, 6, 21)) < 0); 30 | Assert.IsTrue(HDate.make(2011, 10, 9).CompareTo(HDate.make(2011, 3, 21)) > 0); 31 | Assert.IsTrue(HDate.make(2010, 6, 9).CompareTo(HDate.make(2000, 9, 30)) > 0); 32 | Assert.AreEqual(HDate.make(2010, 6, 9).CompareTo(HDate.make(2010, 6, 9)), 0); 33 | } 34 | 35 | [TestMethod] 36 | public void testPlusMinus() 37 | { 38 | Assert.IsTrue(HDate.make(2011, 12, 1).minusDays(0).hequals(HDate.make(2011, 12, 1))); 39 | Assert.IsTrue(HDate.make(2011, 12, 1).minusDays(1).hequals(HDate.make(2011, 11, 30))); 40 | Assert.IsTrue(HDate.make(2011, 12, 1).minusDays(-2).hequals(HDate.make(2011, 12, 3))); 41 | Assert.IsTrue(HDate.make(2011, 12, 1).plusDays(2).hequals(HDate.make(2011, 12, 3))); 42 | Assert.IsTrue(HDate.make(2011, 12, 1).plusDays(31).hequals(HDate.make(2012, 1, 1))); 43 | Assert.IsTrue(HDate.make(2008, 3, 3).minusDays(3).hequals(HDate.make(2008, 2, 29))); 44 | Assert.IsTrue(HDate.make(2008, 3, 3).minusDays(4).hequals(HDate.make(2008, 2, 28))); 45 | } 46 | 47 | [TestMethod] 48 | public void testLeapYear() 49 | { 50 | for (int y = 1900; y <= 2100; y++) 51 | { 52 | if (((y % 4) == 0) && (y != 1900) && (y != 2100)) 53 | Assert.IsTrue(HDate.isLeapYear(y)); 54 | else 55 | Assert.IsFalse(HDate.isLeapYear(y)); 56 | } 57 | } 58 | 59 | [TestMethod] 60 | public void testMidnight() 61 | { 62 | verifyMidnight(HDate.make(2011, 11, 3), "UTC", "2011-11-03T00:00:00Z UTC"); 63 | verifyMidnight(HDate.make(2011, 11, 3), "New_York", "2011-11-03T00:00:00-04:00 New_York"); 64 | verifyMidnight(HDate.make(2011, 12, 15), "Chicago", "2011-12-15T00:00:00-06:00 Chicago"); 65 | verifyMidnight(HDate.make(2008, 2, 29), "Phoenix", "2008-02-29T00:00:00-07:00 Phoenix"); 66 | } 67 | 68 | private void verifyMidnight(HDate date, string tzName, string str) 69 | { 70 | var tz = HTimeZone.make(tzName, false); 71 | // Ignore issues with locally installed timezones. 72 | if (tz == null) 73 | return; 74 | HDateTime ts = date.midnight(tz); 75 | Assert.AreEqual(ts.date, date); 76 | Assert.AreEqual(ts.time.Hour, 0); 77 | Assert.AreEqual(ts.time.Minute, 0); 78 | Assert.AreEqual(ts.time.Second, 0); 79 | Assert.AreEqual(ts.ToString(), str); 80 | Assert.IsTrue(ts.hequals(read(ts.toZinc()))); 81 | Assert.AreEqual(ts.Ticks, ((HDateTime)read(str)).Ticks); 82 | } 83 | 84 | [TestMethod] 85 | public void testZinc() 86 | { 87 | verifyZinc(HDate.make(2011, 6, 7), "2011-06-07"); 88 | verifyZinc(HDate.make(2011, 10, 10), "2011-10-10"); 89 | verifyZinc(HDate.make(2011, 12, 31), "2011-12-31"); 90 | } 91 | 92 | [TestMethod] 93 | [ExpectedException(typeof(FormatException))] 94 | public void testBadZinc() 95 | { 96 | string[] badDateZinc = 97 | { 98 | "2003-xx-02", 99 | "2003-02", 100 | "2003-02-xx" 101 | }; 102 | foreach (string strCurZinc in badDateZinc) 103 | read(strCurZinc); 104 | } 105 | 106 | } 107 | } 108 | 109 | -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HDateTimeRangeTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 3 | // Licensed under the Academic Free License version 3.0 4 | // 5 | // History: 6 | // 16 August 2018 Ian Davies Creation based on Java Toolkit at same time from project-haystack.org downloads 7 | // 8 | using System; 9 | using Microsoft.VisualStudio.TestTools.UnitTesting; 10 | using ProjectHaystack; 11 | 12 | namespace ProjectHaystackTest 13 | { 14 | [TestClass] 15 | public class HDateTimeRangeTest 16 | { 17 | [TestMethod] 18 | public void testRange() 19 | { 20 | HTimeZone ny = HTimeZone.make("New_York", false); 21 | // Ignore issues with locally installed timezones. 22 | if (ny == null) 23 | return; 24 | HDate today = HDate.today(); 25 | HDate yesterday = today.minusDays(1); 26 | HDate x = HDate.make(2011, 7, 4); 27 | HDate y = HDate.make(2011, 11, 4); 28 | HDateTime xa = HDateTime.make(x, HTime.make(2, 30), ny); 29 | HDateTime xb = HDateTime.make(x, HTime.make(22, 5), ny); 30 | 31 | // this week 32 | HDate sun = today; 33 | HDate sat = today; 34 | while (sun.weekday() > DayOfWeek.Sunday) sun = sun.minusDays(1); 35 | while (sat.weekday() < DayOfWeek.Saturday) sat = sat.plusDays(1); 36 | verifyRange(HDateTimeRange.thisWeek(ny), sun, sat); 37 | 38 | // this month 39 | HDate first = today; 40 | HDate last = today; 41 | while (first.Day > 1) first = first.minusDays(1); 42 | while (last.Day < DateTime.DaysInMonth(today.Year, today.Month)) last = last.plusDays(1); 43 | verifyRange(HDateTimeRange.thisMonth(ny), first, last); 44 | 45 | // this year 46 | first = HDate.make(today.Year, 1, 1); 47 | last = HDate.make(today.Year, 12, 31); 48 | verifyRange(HDateTimeRange.thisYear(ny), first, last); 49 | 50 | // last week 51 | HDate prev = today.minusDays(7); 52 | sun = prev; 53 | sat = prev; 54 | while (sun.weekday() > DayOfWeek.Sunday) sun = sun.minusDays(1); 55 | while (sat.weekday() < DayOfWeek.Saturday) sat = sat.plusDays(1); 56 | verifyRange(HDateTimeRange.lastWeek(ny), sun, sat); 57 | 58 | // last month 59 | last = today; 60 | while (last.Month == today.Month) last = last.minusDays(1); 61 | first = HDate.make(last.Year, last.Month, 1); 62 | verifyRange(HDateTimeRange.lastMonth(ny), first, last); 63 | 64 | // last year 65 | first = HDate.make(today.Year - 1, 1, 1); 66 | last = HDate.make(today.Year - 1, 12, 31); 67 | verifyRange(HDateTimeRange.lastYear(ny), first, last); 68 | } 69 | 70 | private void verifyRange(HDateTimeRange r, HDate start, HDate end) 71 | { 72 | Assert.IsTrue(r.Start.date.hequals(start)); 73 | Assert.IsTrue(r.Start.time.hequals(HTime.MIDNIGHT)); 74 | Assert.AreEqual(r.Start.TimeZone.ToString(), "New_York"); 75 | Assert.IsTrue(r.End.date.hequals(end.plusDays(1))); 76 | Assert.IsTrue(r.End.time.hequals( HTime.MIDNIGHT)); 77 | Assert.AreEqual(r.End.TimeZone.ToString(), "New_York"); 78 | } 79 | 80 | private void verifyRange(HDateTimeRange r, HDateTime start, HDateTime end) 81 | { 82 | Assert.IsTrue(r.Start.hequals(start)); 83 | Assert.IsTrue(r.End.hequals(end)); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HDefTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using ProjectHaystack; 4 | 5 | namespace ProjectHaystackTest 6 | { 7 | [TestClass] 8 | public class HDefTest : HValTest 9 | { 10 | [TestMethod] 11 | public void testEquality() 12 | { 13 | Assert.IsTrue(HDef.make("^foo").hequals(HDef.make("^foo"))); 14 | } 15 | 16 | [TestMethod] 17 | public void testZinc() 18 | { 19 | verifyZinc(HDef.make("^testDef"), "^testDef"); 20 | } 21 | 22 | [TestMethod] 23 | [ExpectedException(typeof(ArgumentException))] 24 | public void testBadDefConstruction() 25 | { 26 | string[] badDefs = new string[] 27 | { 28 | "^@a", 29 | "^a b", 30 | "^a\n", 31 | "^@", 32 | "a", 33 | "bcd", 34 | }; 35 | foreach (string strID in badDefs) 36 | HDef.make(strID); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HHisItemTest.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using ProjectHaystack; 3 | 4 | namespace ProjectHaystackTest.BackCompat 5 | { 6 | [TestClass] 7 | public class HHisItemTest : HValTest 8 | { 9 | [TestMethod] 10 | public void gridToItems() 11 | { 12 | // Arrange. 13 | var gridBuilder = new HGridBuilder(); 14 | gridBuilder.addCol("ts"); 15 | gridBuilder.addCol("val"); 16 | gridBuilder.addRow(HDateTime.make(2020, 1, 1, 0, 0, 0, HTimeZone.UTC), HNum.make(10)); 17 | var grid = gridBuilder.toGrid(); 18 | 19 | // Act. 20 | var hisItems = HHisItem.gridToItems(grid); 21 | 22 | // Assert. 23 | Assert.AreEqual(1, hisItems.Length); 24 | Assert.AreEqual(HDateTime.make(2020, 1, 1, 0, 0, 0, HTimeZone.UTC), hisItems[0].TimeStamp); 25 | Assert.AreEqual(HNum.make(10), hisItems[0].hsVal); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HListTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 3 | // Licensed under the Academic Free License version 3.0 4 | // 5 | // History: 6 | // 16 August 2018 Ian Davies Creation based on Java Toolkit at same time from project-haystack.org downloads 7 | // 8 | using System; 9 | using System.Collections.Generic; 10 | using Microsoft.VisualStudio.TestTools.UnitTesting; 11 | using ProjectHaystack; 12 | 13 | namespace ProjectHaystackTest 14 | { 15 | [TestClass] 16 | public class HListTest : HValTest 17 | { 18 | [TestMethod] 19 | public void testEmpty() 20 | { 21 | Assert.IsTrue(HList.EMPTY.hequals(HList.make(new List()))); 22 | Assert.IsTrue(HList.EMPTY.hequals(HList.make(new HVal[0]))); 23 | Assert.AreEqual(HList.EMPTY.size(), 0); 24 | try 25 | { 26 | HList.EMPTY.get(0); 27 | Assert.Fail(); 28 | } 29 | catch (Exception) 30 | { 31 | Assert.IsTrue(true); 32 | } 33 | } 34 | 35 | [TestMethod] 36 | public void testBasics() 37 | { 38 | HRef hrefTest = HRef.make("a"); 39 | HStr str = HStr.make("string"); 40 | List items = new List(); 41 | items.Add(hrefTest); 42 | items.Add(str); 43 | 44 | HList list = HList.make(items); 45 | Assert.AreEqual(list.size(), 2); 46 | Assert.AreEqual(list.get(0), hrefTest); 47 | Assert.AreEqual(list.get(1), str); 48 | } 49 | 50 | [TestMethod] 51 | public void testZinc() 52 | { 53 | verifyZinc(HList.EMPTY, "[]"); 54 | // TODO: more tests 55 | } 56 | 57 | [TestMethod] 58 | public void testJson() 59 | { 60 | // Arrange. 61 | HRef hrefTest = HRef.make("a"); 62 | HStr str = HStr.make("string"); 63 | List items = new List(); 64 | items.Add(hrefTest); 65 | items.Add(str); 66 | HList list = HList.make(items); 67 | 68 | // Act. 69 | var json = list.toJson(); 70 | 71 | // Assert. 72 | Assert.AreEqual("[{\"_kind\":\"ref\",\"val\":\"a\",\"dis\":null},\"string\"]", json); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HMarkerTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 3 | // Licensed under the Academic Free License version 3.0 4 | // 5 | // History: 6 | // 16 August 2018 Ian Davies Creation based on Java Toolkit at same time from project-haystack.org downloads 7 | // 8 | using System; 9 | using Microsoft.VisualStudio.TestTools.UnitTesting; 10 | using ProjectHaystack; 11 | using ProjectHaystack.io; 12 | 13 | namespace ProjectHaystackTest 14 | { 15 | [TestClass] 16 | public class HMarkerTest : HValTest 17 | { 18 | [TestMethod] 19 | public void testEquality() 20 | { 21 | Assert.IsTrue(HMarker.VAL.hequals(HMarker.VAL)); 22 | } 23 | 24 | [TestMethod] 25 | public void testToString() 26 | { 27 | Assert.AreEqual(HMarker.VAL.ToString(), "marker"); 28 | } 29 | 30 | [TestMethod] 31 | public void testZinc() 32 | { 33 | verifyZinc(HMarker.VAL, "M"); 34 | } 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HNumTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 3 | // Licensed under the Academic Free License version 3.0 4 | // 5 | // History: 6 | // 16 August 2018 Ian Davies Creation based on Java Toolkit at same time from project-haystack.org downloads 7 | // 8 | using System; 9 | using System.Globalization; 10 | using System.Threading; 11 | using Microsoft.VisualStudio.TestTools.UnitTesting; 12 | using ProjectHaystack; 13 | 14 | namespace ProjectHaystackTest 15 | { 16 | [TestClass] 17 | public class HNumTest : HValTest 18 | { 19 | [TestMethod] 20 | public void testEquality() 21 | { 22 | Assert.IsTrue(HNum.make(2).hequals(HNum.make(2.0, null))); 23 | Assert.IsFalse(HNum.make(2).hequals(HNum.make(2, "%"))); 24 | Assert.IsFalse(HNum.make(2, "%").hequals(HNum.make(2))); 25 | Assert.IsTrue(HNum.make(0).hequals(HNum.make(0.0))); 26 | } 27 | 28 | [TestMethod] 29 | public void testCompare() 30 | { 31 | Assert.IsTrue(HNum.make(9).compareTo(HNum.make(11)) < 0); 32 | Assert.IsTrue(HNum.make(-3).compareTo(HNum.make(-4)) > 0); 33 | Assert.AreEqual(HNum.make(-23).compareTo(HNum.make(-23)), 0); 34 | } 35 | 36 | [TestMethod] 37 | public void testZinc() 38 | { 39 | verifyZinc(HNum.make(123), "123"); 40 | verifyZinc(HNum.make(123.4, "m/s"), "123.4m/s"); 41 | verifyZinc(HNum.make(9.6, "m/s"), "9.6m/s"); 42 | verifyZinc(HNum.make(-5.2, "\u00b0F"), "-5.2\u00b0F"); 43 | verifyZinc(HNum.make(23, "%"), "23%"); 44 | verifyZinc(HNum.make(2.4e-3, "fl_oz"), "0.0024fl_oz"); 45 | verifyZinc(HNum.make(2.4e5, "$"), "240000$"); 46 | Assert.IsTrue(read("1234.56fl_oz").hequals(HNum.make(1234.56, "fl_oz"))); 47 | Assert.IsTrue(read("0.000028fl_oz").hequals(HNum.make(0.000028, "fl_oz"))); 48 | 49 | // specials 50 | verifyZinc(HNum.make(double.NegativeInfinity), "-INF"); 51 | verifyZinc(HNum.make(double.PositiveInfinity), "INF"); 52 | verifyZinc(HNum.make(double.NaN), "NaN"); 53 | 54 | // verify units never serialized for special values 55 | Assert.AreEqual(HNum.make(double.NaN, "ignore").toZinc(), "NaN"); 56 | Assert.AreEqual(HNum.make(double.PositiveInfinity, "%").toZinc(), "INF"); 57 | Assert.AreEqual(HNum.make(double.NegativeInfinity, "%").toZinc(), "-INF"); 58 | } 59 | 60 | [TestMethod] 61 | public void verifyUnitNames() 62 | { 63 | Assert.IsTrue(HNum.isUnitName(null)); 64 | Assert.IsFalse(HNum.isUnitName("")); 65 | Assert.IsTrue(HNum.isUnitName("x_z")); 66 | Assert.IsFalse(HNum.isUnitName("x z")); 67 | } 68 | 69 | [TestMethod] 70 | public void testFormatDecimalWithDot() 71 | { 72 | string defaultLanguage = CultureInfo.InvariantCulture.ToString(); 73 | Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR"); 74 | verifyZinc(HNum.make(2.4), "2.4"); 75 | Thread.CurrentThread.CurrentCulture = new CultureInfo(defaultLanguage); 76 | } 77 | 78 | [TestMethod] 79 | [ExpectedException(typeof(ArgumentException))] 80 | public void testBadUnitConstruction() 81 | { 82 | string[] badunitNames = new string[] 83 | { 84 | "foo bar", 85 | "foo,bar" 86 | }; 87 | foreach (string curUnit in badunitNames) 88 | HNum.make(123.4, curUnit); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HRefTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 3 | // Licensed under the Academic Free License version 3.0 4 | // 5 | // History: 6 | // 16 August 2018 Ian Davies Creation based on Java Toolkit at same time from project-haystack.org downloads 7 | // 8 | using System; 9 | using Microsoft.VisualStudio.TestTools.UnitTesting; 10 | using ProjectHaystack; 11 | 12 | namespace ProjectHaystackTest 13 | { 14 | [TestClass] 15 | public class HRefTest : HValTest 16 | { 17 | [TestMethod] 18 | public void testEquality() 19 | { 20 | Assert.IsTrue(HRef.make("foo").hequals(HRef.make("foo"))); 21 | Assert.IsTrue(HRef.make("foo").hequals(HRef.make("foo", "Foo"))); 22 | Assert.IsFalse(HRef.make("foo").hequals(HRef.make("Foo"))); 23 | Assert.IsFalse(HRef.nullRef.hequals(HRef.nullRef)); 24 | } 25 | 26 | [TestMethod] 27 | public void testZinc() 28 | { 29 | verifyZinc(HRef.make("1234-5678.foo:bar"), "@1234-5678.foo:bar"); 30 | verifyZinc(HRef.make("1234-5678", "Foo Bar"), "@1234-5678 \"Foo Bar\""); 31 | verifyZinc(HRef.make("1234-5678", "Foo \"Bar\""), "@1234-5678 \"Foo \\\"Bar\\\"\""); 32 | } 33 | 34 | [TestMethod] 35 | public void testIsId() 36 | { 37 | Assert.IsFalse(HRef.isId("")); 38 | Assert.IsFalse(HRef.isId("%")); 39 | Assert.IsTrue(HRef.isId("a")); 40 | Assert.IsTrue(HRef.isId("a-b:c")); 41 | Assert.IsFalse(HRef.isId("a b")); 42 | Assert.IsFalse(HRef.isId("a\u0129b")); 43 | } 44 | 45 | [TestMethod] 46 | [ExpectedException(typeof(ArgumentException))] 47 | public void testBadRefConstruction() 48 | { 49 | string[] badRefs = new string[] 50 | { 51 | "@a", 52 | "a b", 53 | "a\n", 54 | "@" 55 | }; 56 | foreach (string strID in badRefs) 57 | HRef.make(strID); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HStrTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 3 | // Licensed under the Academic Free License version 3.0 4 | // 5 | // History: 6 | // 16 August 2018 Ian Davies Creation based on Java Toolkit at same time from project-haystack.org downloads 7 | // 8 | using System; 9 | using Microsoft.VisualStudio.TestTools.UnitTesting; 10 | using ProjectHaystack; 11 | 12 | namespace ProjectHaystackTest 13 | { 14 | [TestClass] 15 | public class HStrTest : HValTest 16 | { 17 | [TestMethod] 18 | public void testEquality() 19 | { 20 | Assert.IsTrue(HStr.make("a").hequals(HStr.make("a"))); 21 | Assert.IsFalse(HStr.make("a").hequals( HStr.make("b"))); 22 | Assert.IsTrue(HStr.make("").hequals(HStr.make(""))); 23 | } 24 | 25 | [TestMethod] 26 | public void testCompare() 27 | { 28 | Assert.IsTrue(HStr.make("abc").CompareTo(HStr.make("z")) < 0); 29 | Assert.AreEqual(HStr.make("Foo").CompareTo(HStr.make("Foo")), 0); 30 | } 31 | 32 | [TestMethod] 33 | public void testZinc() 34 | { 35 | verifyZinc(HStr.make("hello"), "\"hello\""); 36 | verifyZinc(HStr.make("_ \\ \" \n \r \t \u0011 _"), "\"_ \\\\ \\\" \\n \\r \\t \\u0011 _\""); 37 | verifyZinc(HStr.make("\u0abc"), "\"\u0abc\""); 38 | } 39 | 40 | [TestMethod] 41 | public void testHex() 42 | { 43 | // Changed test - unicode code must be valid not random like original test. - this is "NA" 44 | Assert.IsTrue(read("\"[\\u004e \\u0041]\"").hequals(HStr.make("[\u004e \u0041]"))); 45 | Assert.IsTrue(read("\"[\\u004E \\u0041]\"").hequals(HStr.make("[\u004E \u0041]"))); 46 | } 47 | 48 | [TestMethod] 49 | [ExpectedException(typeof(FormatException))] 50 | public void testNoEndQuote() 51 | { 52 | read("\"end..."); 53 | } 54 | 55 | [TestMethod] 56 | [ExpectedException(typeof(ArgumentException))] 57 | public void testBadUnicodeEsc() 58 | { 59 | read("\"\\u1x34\""); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HTimeTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 3 | // Licensed under the Academic Free License version 3.0 4 | // 5 | // History: 6 | // 16 August 2018 Ian Davies Creation based on Java Toolkit at same time from project-haystack.org downloads 7 | // 8 | using System; 9 | using Microsoft.VisualStudio.TestTools.UnitTesting; 10 | using ProjectHaystack; 11 | 12 | namespace ProjectHaystackTest 13 | { 14 | [TestClass] 15 | public class HTimeTest : HValTest 16 | { 17 | [TestMethod] 18 | public void testEquality() 19 | { 20 | Assert.IsTrue(HTime.make(1, 2, 3, 4).hequals(HTime.make(1, 2, 3, 4))); 21 | Assert.IsFalse(HTime.make(1, 2, 3, 4).hequals(HTime.make(9, 2, 3, 4))); 22 | Assert.IsFalse(HTime.make(1, 2, 3, 4).hequals( HTime.make(1, 9, 3, 4))); 23 | Assert.IsFalse(HTime.make(1, 2, 3, 4).hequals(HTime.make(1, 2, 9, 9))); 24 | } 25 | 26 | [TestMethod] 27 | public void testCompare() 28 | { 29 | Assert.IsTrue(HTime.make(0, 0, 0, 0).CompareTo(HTime.make(0, 0, 0, 9)) < 0); 30 | Assert.IsTrue(HTime.make(0, 0, 0, 0).CompareTo(HTime.make(0, 0, 1, 0)) < 0); 31 | Assert.IsTrue(HTime.make(0, 1, 0, 0).CompareTo(HTime.make(0, 0, 0, 0)) > 0); 32 | Assert.IsTrue(HTime.make(0, 0, 0, 0).CompareTo(HTime.make(2, 0, 0, 0)) < 0); 33 | Assert.AreEqual(HTime.make(2, 0, 0, 0).CompareTo(HTime.make(2, 0, 0, 0)), 0); 34 | } 35 | 36 | [TestMethod] 37 | public void testZinc() 38 | { 39 | verifyZinc(HTime.make(2, 3), "02:03:00"); 40 | verifyZinc(HTime.make(2, 3, 4), "02:03:04"); 41 | verifyZinc(HTime.make(2, 3, 4, 5), "02:03:04.005"); 42 | verifyZinc(HTime.make(2, 3, 4, 56), "02:03:04.056"); 43 | verifyZinc(HTime.make(2, 3, 4, 109), "02:03:04.109"); 44 | verifyZinc(HTime.make(2, 3, 10, 109), "02:03:10.109"); 45 | verifyZinc(HTime.make(2, 10, 59), "02:10:59"); 46 | verifyZinc(HTime.make(10, 59, 30), "10:59:30"); 47 | verifyZinc(HTime.make(23, 59, 59, 999), "23:59:59.999"); 48 | verifyZinc(HTime.make(3, 20, 0), "03:20:00"); 49 | Assert.IsTrue(HTime.make("10:04:19.181511").hequals( HTime.make(10, 04, 19, 181))); 50 | } 51 | 52 | [TestMethod] 53 | [ExpectedException(typeof(Exception))] 54 | public void testBadZinc() 55 | { 56 | string[] badZincs = new string[] 57 | { 58 | "13:xx:00", 59 | "13:45:0x", 60 | "13:45:00.", 61 | "13:45:00.x" 62 | }; 63 | foreach (string zinc in badZincs) 64 | read(zinc); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HTimeZoneTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using ProjectHaystack; 4 | 5 | namespace ProjectHaystackTest 6 | { 7 | [TestClass] 8 | public class HTimeZoneTest : HaystackTest 9 | { 10 | [TestMethod] 11 | public void make_utc() 12 | { 13 | var tz = HTimeZone.make("UTC", false); 14 | Assert.IsTrue(new[] { "UTC", "Etc/UTC" }.Contains(tz.dntz.Id)); 15 | } 16 | 17 | [TestMethod] 18 | public void make_sidney() 19 | { 20 | var tz = HTimeZone.make("Sydney", false); 21 | Assert.IsTrue(new[] { "AUS Eastern Standard Time", "Australia/Sydney" }.Contains(tz.dntz.Id)); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HTzTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 3 | // Licensed under the Academic Free License version 3.0 4 | // 5 | // History: 6 | // 16 August 2018 Ian Davies Creation based on Java Toolkit at same time from project-haystack.org downloads 7 | // 8 | using System; 9 | using System.Linq; 10 | using Microsoft.VisualStudio.TestTools.UnitTesting; 11 | using ProjectHaystack; 12 | 13 | namespace ProjectHaystackTest 14 | { 15 | [TestClass] 16 | public class HTzTest 17 | { 18 | [TestMethod] 19 | public void testTz_NewYork() 20 | { 21 | verifyTz("New_York", "Eastern Standard Time", "America/New_York"); 22 | } 23 | 24 | [TestMethod] 25 | public void testTz_Chicago() 26 | { 27 | verifyTz("Chicago", "Central Standard Time", "America/Chicago"); 28 | } 29 | 30 | [TestMethod] 31 | public void testTz_Phoenix() 32 | { 33 | verifyTz("Phoenix", "US Mountain Standard Time", "America/Phoenix"); 34 | } 35 | 36 | [TestMethod] 37 | public void testTz_London() 38 | { 39 | verifyTz("London", "GMT Standard Time", "Europe/London"); 40 | } 41 | 42 | [TestMethod] 43 | public void testTz_UTC() 44 | { 45 | verifyTz("UTC", "UTC", "Etc/UTC"); 46 | } 47 | 48 | [TestMethod] 49 | public void testTz_GMT() 50 | { 51 | verifyTz("GMT", "UTC", "GMT"); 52 | } 53 | 54 | [TestMethod] 55 | public void testTz_Rel() 56 | { 57 | verifyTz("Rel", "UTC", "GMT"); // GMT 58 | } 59 | 60 | private void verifyTz(string name, params string[] dntzIds) 61 | { 62 | HTimeZone tz = HTimeZone.make(name, false); 63 | // Ignore issues with locally installed timezones. 64 | if (tz == null) 65 | return; 66 | TimeZoneInfo dntz = tz.dntz; 67 | Assert.AreEqual(tz.ToString(), name); 68 | Assert.IsTrue(dntzIds.Contains(dntz.Id), $"{dntz.Id} not in [{string.Join(", ", dntzIds)}]"); 69 | // TODO: What is this testing? Move into another test? 70 | //TimeZoneInfo dntzByID = TimeZoneConverter.TZConvert.GetTimeZoneInfo(dntz.Id); 71 | //Assert.IsTrue(tz.hequals(HTimeZone.make(dntzByID, false)), $"{tz} does not equal {dntzByID}"); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HUriTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 3 | // Licensed under the Academic Free License version 3.0 4 | // 5 | // History: 6 | // 16 August 2018 Ian Davies Creation based on Java Toolkit at same time from project-haystack.org downloads 7 | // 8 | using System; 9 | using Microsoft.VisualStudio.TestTools.UnitTesting; 10 | using ProjectHaystack; 11 | 12 | namespace ProjectHaystackTest 13 | { 14 | [TestClass] 15 | public class HUriTest : HValTest 16 | { 17 | [TestMethod] 18 | public void testEquality() 19 | { 20 | Assert.IsTrue(HUri.make("a").hequals(HUri.make("a"))); 21 | Assert.IsFalse(HUri.make("a").hequals(HUri.make("b"))); 22 | Assert.IsTrue(HUri.make("") == HUri.make("")); 23 | } 24 | 25 | [TestMethod] 26 | public void testCompare() 27 | { 28 | Assert.IsTrue(HUri.make("abc").CompareTo(HUri.make("z")) < 0); 29 | Assert.AreEqual(HUri.make("Foo").CompareTo(HUri.make("Foo")), 0); 30 | } 31 | 32 | [TestMethod] 33 | public void testZinc() 34 | { 35 | verifyZinc(HUri.make("http://foo.com/f?q"), "`http://foo.com/f?q`"); 36 | verifyZinc(HUri.make("a$b"), "`a$b`"); 37 | verifyZinc(HUri.make("a`b"), "`a\\`b`"); 38 | verifyZinc(HUri.make("http\\:a\\?b"), "`http\\:a\\?b`"); 39 | verifyZinc(HUri.make("\u01ab.txt"), "`\u01ab.txt`"); 40 | } 41 | 42 | [TestMethod] 43 | [ExpectedException(typeof(FormatException))] 44 | public void testBadZinc() 45 | { 46 | string[] badZincs = new string[] 47 | { 48 | "`no end", 49 | "`new\nline`" 50 | }; 51 | foreach (string zinc in badZincs) 52 | read(zinc); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HValTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 3 | // Licensed under the Academic Free License version 3.0 4 | // 5 | // History: 6 | // 16 August 2018 Ian Davies Creation based on Java Toolkit at same time from project-haystack.org downloads 7 | // 8 | using Microsoft.VisualStudio.TestTools.UnitTesting; 9 | using ProjectHaystack; 10 | using ProjectHaystack.io; 11 | using M = ProjectHaystack.HaystackValueMapper; 12 | 13 | namespace ProjectHaystackTest 14 | { 15 | [TestClass] 16 | public abstract class HValTest : HaystackTest 17 | { 18 | protected void verifyZinc(HVal val, string s) 19 | { 20 | Assert.AreEqual(val.toZinc(), s); 21 | Assert.IsTrue(read(s).hequals(val)); 22 | } 23 | 24 | protected HVal read(string s) 25 | { 26 | return M.Map(ZincReader.ReadValue(s)); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HXStrTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using ProjectHaystack; 4 | 5 | namespace ProjectHaystackTest 6 | { 7 | [TestClass] 8 | public class HXStrTest : HValTest 9 | { 10 | [TestMethod] 11 | public void testTypeStartsWithUpper() 12 | { 13 | HXStr.decode("Type", "a"); 14 | Assert.ThrowsException(() => HXStr.decode("type", "a")); 15 | } 16 | 17 | [TestMethod] 18 | public void testTypeContainsValidCharacters() 19 | { 20 | HXStr.decode("TyP0_s", "a"); 21 | Assert.ThrowsException(() => HXStr.decode("T.", "a")); 22 | Assert.ThrowsException(() => HXStr.decode("T,", "a")); 23 | } 24 | 25 | [TestMethod] 26 | public void testEquality() 27 | { 28 | Assert.IsTrue(HXStr.decode("Type", "a").hequals(HXStr.decode("Type", "a"))); 29 | Assert.IsFalse(HXStr.decode("X", "a").hequals(HXStr.decode("X", "b"))); 30 | Assert.IsTrue(HXStr.decode("X", "").hequals(HXStr.decode("X", ""))); 31 | } 32 | 33 | [TestMethod] 34 | public void testCompare() 35 | { 36 | Assert.IsTrue(HXStr.decode("Type", "abc").CompareTo(HXStr.decode("Type", "z")) < 0); 37 | Assert.AreEqual(HXStr.decode("Type", "Foo").CompareTo(HXStr.decode("Type", "Foo")), 0); 38 | } 39 | 40 | [TestMethod] 41 | public void testZinc() 42 | { 43 | verifyZinc(HXStr.decode("Type", "hello"), "Type(\"hello\")"); 44 | verifyZinc(HXStr.decode("Type", "\u0abc"), "Type(\"\u0abc\")"); 45 | } 46 | 47 | [TestMethod] 48 | public void testHex() 49 | { 50 | // Changed test - unicode code must be valid not random like original test. - this is "NA" 51 | Assert.IsTrue(read("Type(\"[\\u004e \\u0041]\")").hequals(HXStr.decode("Type", "[\u004e \u0041]"))); 52 | Assert.IsTrue(read("Type(\"[\\u004E \\u0041]\")").hequals(HXStr.decode("Type", "[\u004E \u0041]"))); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/HaystackTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 3 | // Licensed under the Academic Free License version 3.0 4 | // 5 | // History: 6 | // 16 August 2018 Ian Davies Creation based on Java Toolkit at same time from project-haystack.org downloads 7 | // 8 | using System; 9 | using Microsoft.VisualStudio.TestTools.UnitTesting; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | using System.Text; 13 | using System.Threading.Tasks; 14 | using ProjectHaystack; 15 | 16 | namespace ProjectHaystackTest 17 | { 18 | public abstract class HaystackTest 19 | { 20 | protected virtual HNum n(long val) { return HNum.make(val); } 21 | protected virtual HNum n(double val) { return HNum.make(val); } 22 | protected virtual HNum n(double val, string unit) { return HNum.make(val, unit); } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/ProjectHaystackTest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp2.1 5 | 2.1.19 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/Util/UtilTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017, SkyFoundry LLC 3 | // Licensed under the Academic Free License version 3.0 4 | // 5 | // History: 6 | // 26 Jun 2017 Hank Weber Creation 7 | // 8 | 9 | using System; 10 | using Microsoft.VisualStudio.TestTools.UnitTesting; 11 | using System.Security.Cryptography; 12 | 13 | namespace ProjectHaystackTest.Util 14 | { 15 | using Base64 = ProjectHaystack.Util.Base64; 16 | using Pbkdf2 = ProjectHaystack.Util.Pbkdf2; 17 | 18 | [TestClass] 19 | public class UtilTest 20 | { 21 | private static string RandomString() 22 | { 23 | Guid g = Guid.NewGuid(); 24 | string GuidString = Convert.ToBase64String(g.ToByteArray()); 25 | GuidString = GuidString.Replace("=", ""); 26 | GuidString = GuidString.Replace("+", ""); 27 | return GuidString; 28 | } 29 | 30 | [TestMethod] 31 | public void Base64Test() 32 | { 33 | for (int i = 0; i < 1000; i++) 34 | { 35 | string s1 = RandomString(); 36 | string enc = Base64.STANDARD.EncodeUtf8(s1); 37 | string s2 = Base64.STANDARD.decodeUTF8(enc); 38 | Assert.AreEqual(s1, s2); 39 | 40 | enc = Base64.STANDARD.Encode(s1); 41 | s2 = Base64.STANDARD.Decode(enc); 42 | Assert.AreEqual(s1, s2); 43 | 44 | enc = Base64.URI.EncodeUtf8(s1); 45 | s2 = Base64.URI.decodeUTF8(enc); 46 | Assert.AreEqual(s1, s2); 47 | 48 | enc = Base64.URI.Encode(s1); 49 | s2 = Base64.URI.Decode(enc); 50 | Assert.AreEqual(s1, s2); 51 | } 52 | } 53 | 54 | 55 | public void DoPbkTest(string password, string salt, int iterations, int dkLen, string expected) 56 | { 57 | using (var hmac = new HMACSHA256()) 58 | { 59 | var mine = new Pbkdf2(hmac, System.Text.Encoding.UTF8.GetBytes(password), System.Text.Encoding.UTF8.GetBytes(salt), iterations); 60 | sbyte[] result = mine.GetBytes(dkLen); 61 | byte[] usResult = (byte[])(Array)result; 62 | String hex = BitConverter.ToString(usResult); 63 | Assert.AreEqual(hex, expected); 64 | } 65 | } 66 | 67 | [TestMethod] 68 | public void PbkTest() 69 | { 70 | DoPbkTest("password", "salt", 1, 32, "12-0F-B6-CF-FC-F8-B3-2C-43-E7-22-52-56-C4-F8-37-A8-65-48-C9-2C-CC-35-48-08-05-98-7C-B7-0B-E1-7B"); 71 | DoPbkTest("password", "salt", 2, 32, "AE-4D-0C-95-AF-6B-46-D3-2D-0A-DF-F9-28-F0-6D-D0-2A-30-3F-8E-F3-C2-51-DF-D6-E2-D8-5A-95-47-4C-43"); 72 | DoPbkTest("password", "salt", 4096, 32, "C5-E4-78-D5-92-88-C8-41-AA-53-0D-B6-84-5C-4C-8D-96-28-93-A0-01-CE-4E-11-A4-96-38-73-AA-98-13-4A"); 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/BackCompat/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /ProjectHaystackTest/Mocks/HttpClientMockBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Net.Http; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | using Moq; 10 | using Moq.Protected; 11 | using ProjectHaystack; 12 | using ProjectHaystack.io; 13 | 14 | namespace ProjectHaystackTest.Mocks 15 | { 16 | public class HttpClientMockBuilder 17 | { 18 | private readonly Uri _baseUri; 19 | private readonly Mock _httpMessageHanderMock = new Mock(); 20 | private readonly List>> _requestHandlers = new List>>(); 21 | 22 | public HttpClientMockBuilder(Uri baseUri) 23 | { 24 | _baseUri = baseUri; 25 | } 26 | 27 | public HttpClient Build() 28 | { 29 | _httpMessageHanderMock 30 | .Protected() 31 | .Setup>("SendAsync", ItExpr.IsAny(), ItExpr.IsAny()) 32 | .Returns((request, _) => 33 | { 34 | foreach (var requestHandler in _requestHandlers) 35 | { 36 | var response = requestHandler(request); 37 | if (response != null) 38 | { 39 | return response; 40 | } 41 | } 42 | throw new Exception("Unexpected request"); 43 | }); 44 | return new HttpClient(_httpMessageHanderMock.Object); 45 | } 46 | 47 | public HttpClientMockBuilder WithBasicAuthentication(string allowedBasicAuth) 48 | { 49 | _requestHandlers.Add(request => 50 | { 51 | if (request.Headers.Authorization == null) 52 | { 53 | return null; 54 | } 55 | if (request.Headers.Authorization.Scheme == "HELLO") 56 | { 57 | var response = new HttpResponseMessage(); 58 | response.Headers.Add("WWW-Authenticate", "basic"); 59 | return Task.FromResult(response); 60 | } 61 | if (request.Headers.Authorization.Scheme == "Basic" && request.RequestUri == new Uri(_baseUri, "about")) 62 | { 63 | if (request.Headers.Authorization.Parameter == allowedBasicAuth) 64 | { 65 | return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)); 66 | } 67 | return Task.FromResult(new HttpResponseMessage(HttpStatusCode.Unauthorized)); 68 | } 69 | return null; 70 | }); 71 | 72 | return this; 73 | } 74 | 75 | public HttpClientMockBuilder WithReadAsync(string expectedFilter, HaystackGrid response) 76 | { 77 | _requestHandlers.Add(async request => 78 | { 79 | var relativeUri = _baseUri.MakeRelativeUri(request.RequestUri); 80 | if (relativeUri.OriginalString != "read") 81 | { 82 | return null; 83 | } 84 | var reader = new ZincReader(await request.Content.ReadAsStringAsync()); 85 | var grid = reader.ReadValue(); 86 | var filter = grid.Rows.First().Get("filter").Value; 87 | if (filter != expectedFilter) 88 | { 89 | return null; 90 | } 91 | using (var stream = new MemoryStream()) 92 | using (var streamWriter = new StreamWriter(stream)) 93 | { 94 | var writer = new ZincWriter(streamWriter); 95 | writer.WriteValue(response); 96 | streamWriter.Flush(); 97 | stream.Position = 0; 98 | return new HttpResponseMessage 99 | { 100 | Content = new StringContent(await new StreamReader(stream).ReadToEndAsync()), 101 | }; 102 | } 103 | }); 104 | 105 | return this; 106 | } 107 | 108 | public HttpClientMockBuilder WithRequestHandler(Func> handleRequest) 109 | { 110 | _requestHandlers.Add(handleRequest); 111 | 112 | return this; 113 | } 114 | } 115 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/ProjectHaystackTest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /ProjectHaystackTest/Validation/HaystackValidatorTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using ProjectHaystack.Validation; 3 | 4 | namespace ProjectHaystackTest.Validation 5 | { 6 | [TestClass] 7 | public class HaystackValidatorTests 8 | { 9 | [TestMethod] 10 | public void TestIsTagName() 11 | { 12 | Assert.IsFalse(HaystackValidator.IsTagName("")); 13 | Assert.IsFalse(HaystackValidator.IsTagName("A")); 14 | Assert.IsFalse(HaystackValidator.IsTagName(" ")); 15 | Assert.IsTrue(HaystackValidator.IsTagName("a")); 16 | Assert.IsTrue(HaystackValidator.IsTagName("a_B_19")); 17 | Assert.IsFalse(HaystackValidator.IsTagName("a b")); 18 | Assert.IsFalse(HaystackValidator.IsTagName("a\u0128")); 19 | Assert.IsFalse(HaystackValidator.IsTagName("a\u0129x")); 20 | Assert.IsFalse(HaystackValidator.IsTagName("a\uabcdx")); 21 | Assert.IsTrue(HaystackValidator.IsTagName("^tag")); 22 | } 23 | 24 | [TestMethod] 25 | public void TestIsId() 26 | { 27 | Assert.IsFalse(HaystackValidator.IsReferenceId("")); 28 | Assert.IsFalse(HaystackValidator.IsReferenceId("%")); 29 | Assert.IsTrue(HaystackValidator.IsReferenceId("a")); 30 | Assert.IsTrue(HaystackValidator.IsReferenceId("a-b:c")); 31 | Assert.IsFalse(HaystackValidator.IsReferenceId("a b")); 32 | Assert.IsFalse(HaystackValidator.IsReferenceId("a\u0129b")); 33 | } 34 | 35 | [TestMethod] 36 | public void VerifyUnitNames() 37 | { 38 | Assert.IsTrue(HaystackValidator.IsUnitName(null)); 39 | Assert.IsFalse(HaystackValidator.IsUnitName("")); 40 | Assert.IsTrue(HaystackValidator.IsUnitName("x_z")); 41 | Assert.IsFalse(HaystackValidator.IsUnitName("x z")); 42 | Assert.IsTrue(HaystackValidator.IsUnitName("ft²")); 43 | } 44 | 45 | [TestMethod] 46 | public void TestIsLatitude() 47 | { 48 | Assert.IsFalse(HaystackValidator.IsLatitude(-91m)); 49 | Assert.IsTrue(HaystackValidator.IsLatitude(-90m)); 50 | Assert.IsTrue(HaystackValidator.IsLatitude(-89m)); 51 | Assert.IsTrue(HaystackValidator.IsLatitude(90m)); 52 | Assert.IsFalse(HaystackValidator.IsLatitude(91m)); 53 | } 54 | 55 | [TestMethod] 56 | public void TestIsLongitude() 57 | { 58 | Assert.IsFalse(HaystackValidator.IsLongitude(-181m)); 59 | Assert.IsTrue(HaystackValidator.IsLongitude(-179.99m)); 60 | Assert.IsTrue(HaystackValidator.IsLongitude(180m)); 61 | Assert.IsFalse(HaystackValidator.IsLongitude(181m)); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/Values/HaystackBinaryTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using ProjectHaystack; 3 | 4 | namespace ProjectHaystackTest 5 | { 6 | [TestClass] 7 | public class HaystackBinaryTests 8 | { 9 | [TestMethod] 10 | public void TestEquality() 11 | { 12 | var bin1 = new HaystackBinary("text/plain"); 13 | var bin2 = new HaystackBinary("text/plain"); 14 | var bin3 = new HaystackBinary("text/xml"); 15 | 16 | Assert.AreEqual(bin1, bin2); 17 | Assert.AreNotEqual(bin1, bin3); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/Values/HaystackBooleanTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using ProjectHaystack; 3 | 4 | namespace ProjectHaystackTest 5 | { 6 | [TestClass] 7 | public class HaystackBooleanTests 8 | { 9 | [TestMethod] 10 | public void TestEquality() 11 | { 12 | Assert.IsTrue(new HaystackBoolean(true).Equals(new HaystackBoolean(true))); 13 | Assert.IsFalse(new HaystackBoolean(true).Equals(new HaystackBoolean(false))); 14 | Assert.IsTrue(new HaystackBoolean(true).Equals(new HaystackBoolean(true))); 15 | Assert.IsTrue(new HaystackBoolean(false).Equals(new HaystackBoolean(false))); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/Values/HaystackCoordinateTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using ProjectHaystack; 4 | using ProjectHaystack.io; 5 | 6 | namespace ProjectHaystackTest 7 | { 8 | [TestClass] 9 | public class HaystackCoordinateTest 10 | { 11 | [TestMethod] 12 | public void TestLatBoundaries() 13 | { 14 | VerifyCoord(90, 123, "C(90,123)"); 15 | VerifyCoord(-90, 123, "C(-90,123)"); 16 | VerifyCoord(89.888999m, 123, "C(89.888999,123)"); 17 | VerifyCoord(-89.888999m, 123, "C(-89.888999,123)"); 18 | } 19 | 20 | [TestMethod] 21 | public void TestLonBoundaries() 22 | { 23 | VerifyCoord(45, 180, "C(45,180)"); 24 | VerifyCoord(45, -180, "C(45,-180)"); 25 | VerifyCoord(45, 179.999129m, "C(45,179.999129)"); 26 | VerifyCoord(45, -179.999129m, "C(45,-179.999129)"); 27 | } 28 | 29 | [TestMethod] 30 | public void TestDecimalPlaces() 31 | { 32 | VerifyCoord(9.1m, -8.1m, "C(9.1,-8.1)"); 33 | VerifyCoord(9.12m, -8.13m, "C(9.12,-8.13)"); 34 | VerifyCoord(9.123m, -8.134m, "C(9.123,-8.134)"); 35 | VerifyCoord(9.1234m, -8.1346m, "C(9.1234,-8.1346)"); 36 | VerifyCoord(9.12345m, -8.13456m, "C(9.12345,-8.13456)"); 37 | VerifyCoord(9.123452m, -8.134567m, "C(9.123452,-8.134567)"); 38 | } 39 | 40 | [TestMethod] 41 | public void TestZeroBoundaries() 42 | { 43 | VerifyCoord(0, 0, "C(0,0)"); 44 | VerifyCoord(0.3m, -0.3m, "C(0.3,-0.3)"); 45 | VerifyCoord(0.03m, -0.03m, "C(0.03,-0.03)"); 46 | VerifyCoord(0.003m, -0.003m, "C(0.003,-0.003)"); 47 | VerifyCoord(0.0003m, -0.0003m, "C(0.0003,-0.0003)"); 48 | VerifyCoord(0.02003m, -0.02003m, "C(0.02003,-0.02003)"); 49 | VerifyCoord(0.020003m, -0.020003m, "C(0.020003,-0.020003)"); 50 | VerifyCoord(0.000123m, -0.000123m, "C(0.000123,-0.000123)"); 51 | VerifyCoord(7.000123m, -7.000123m, "C(7.000123,-7.000123)"); 52 | } 53 | 54 | [TestMethod] 55 | public void TestMakeErrors() 56 | { 57 | try { new HaystackCoordinate(91, 12); Assert.Fail(); } catch (ArgumentException) { Assert.IsTrue(true); } 58 | try { new HaystackCoordinate(-90.2m, 12); Assert.Fail(); } catch (ArgumentException) { Assert.IsTrue(true); } 59 | try { new HaystackCoordinate(13, 180.009m); Assert.Fail(); } catch (ArgumentException) { Assert.IsTrue(true); } 60 | try { new HaystackCoordinate(13, -181); Assert.Fail(); } catch (ArgumentException) { Assert.IsTrue(true); } 61 | } 62 | 63 | private void VerifyCoord(decimal latitude, decimal longitude, string s) 64 | { 65 | var coordinate = new HaystackCoordinate(latitude, longitude); 66 | Assert.AreEqual(latitude, coordinate.Latitude); 67 | Assert.AreEqual(longitude, coordinate.Longitude); 68 | Assert.AreEqual(s, ZincWriter.ToZinc(coordinate)); 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/Values/HaystackDateTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using ProjectHaystack; 3 | 4 | namespace ProjectHaystackTest 5 | { 6 | [TestClass] 7 | public class HaystackDateTests 8 | { 9 | [TestMethod] 10 | public void TestEquality() 11 | { 12 | Assert.IsTrue(new HaystackDate(2011, 6, 7).Equals(new HaystackDate(2011, 6, 7))); 13 | Assert.IsFalse(new HaystackDate(2011, 6, 7).Equals(new HaystackDate(2011, 6, 8))); 14 | Assert.IsFalse(new HaystackDate(2011, 6, 7).Equals(new HaystackDate(2011, 2, 7))); 15 | Assert.IsFalse(new HaystackDate(2011, 6, 7).Equals(new HaystackDate(2009, 6, 7))); 16 | } 17 | 18 | [TestMethod] 19 | public void TestCompare() 20 | { 21 | Assert.IsTrue(new HaystackDate(2011, 6, 9).CompareTo(new HaystackDate(2011, 6, 21)) < 0); 22 | Assert.IsTrue(new HaystackDate(2011, 10, 9).CompareTo(new HaystackDate(2011, 3, 21)) > 0); 23 | Assert.IsTrue(new HaystackDate(2010, 6, 9).CompareTo(new HaystackDate(2000, 9, 30)) > 0); 24 | Assert.AreEqual(new HaystackDate(2010, 6, 9).CompareTo(new HaystackDate(2010, 6, 9)), 0); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/Values/HaystackDateTimeTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using ProjectHaystack; 4 | 5 | namespace ProjectHaystackTest 6 | { 7 | [TestClass] 8 | public class HaystackDateTimeTests 9 | { 10 | public static HaystackTimeZone utc = HaystackTimeZone.UTC; 11 | public static HaystackTimeZone london = new HaystackTimeZone("London"); 12 | 13 | [TestMethod] 14 | public void TestEquality() 15 | { 16 | Assert.IsTrue(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), utc).Equals(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), utc))); 17 | Assert.IsFalse(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), utc).Equals(new HaystackDateTime(new DateTime(2009, 1, 2, 3, 4, 5), utc))); 18 | Assert.IsFalse(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), utc).Equals(new HaystackDateTime(new DateTime(2011, 9, 2, 3, 4, 5), utc))); 19 | Assert.IsFalse(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), utc).Equals(new HaystackDateTime(new DateTime(2011, 1, 9, 3, 4, 5), utc))); 20 | Assert.IsFalse(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), utc).Equals(new HaystackDateTime(new DateTime(2011, 1, 2, 9, 4, 5), utc))); 21 | Assert.IsFalse(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), utc).Equals(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 9, 5), utc))); 22 | Assert.IsFalse(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), utc).Equals(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 9), utc))); 23 | Assert.IsFalse(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), utc).Equals(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), london))); 24 | } 25 | 26 | [TestMethod] 27 | public void TestCompare() 28 | { 29 | Assert.AreEqual(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), utc).CompareTo(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), utc)), 0); 30 | Assert.IsTrue(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), utc).CompareTo(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 6), utc)) < 0); 31 | Assert.IsTrue(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), utc).CompareTo(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 5, 5), utc)) < 0); 32 | Assert.IsTrue(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), utc).CompareTo(new HaystackDateTime(new DateTime(2011, 1, 2, 4, 4, 5), utc)) < 0); 33 | Assert.IsTrue(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), utc).CompareTo(new HaystackDateTime(new DateTime(2011, 1, 3, 3, 4, 5), utc)) < 0); 34 | Assert.IsTrue(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), utc).CompareTo(new HaystackDateTime(new DateTime(2011, 2, 2, 3, 4, 5), utc)) < 0); 35 | Assert.IsTrue(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), utc).CompareTo(new HaystackDateTime(new DateTime(2012, 1, 2, 3, 4, 5), utc)) < 0); 36 | Assert.IsTrue(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), utc).CompareTo(new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 0), utc)) > 0); 37 | } 38 | 39 | [TestMethod] 40 | public void TestTimeZoneOffset() 41 | { 42 | Assert.AreEqual(TimeSpan.FromHours(0), new HaystackDateTime(new DateTime(2011, 1, 2, 3, 4, 5), london).Value.Offset); 43 | Assert.AreEqual(TimeSpan.FromHours(1), new HaystackDateTime(new DateTime(2011, 7, 2, 3, 4, 5), london).Value.Offset); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/Values/HaystackDefinitionTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using ProjectHaystack; 4 | 5 | namespace ProjectHaystackTest 6 | { 7 | [TestClass] 8 | public class HaystackDefinitionTests 9 | { 10 | [TestMethod] 11 | public void TestEquality() 12 | { 13 | Assert.IsTrue(new HaystackDefinition("^foo").Equals(new HaystackDefinition("^foo"))); 14 | Assert.IsFalse(new HaystackDefinition("^foo").Equals(new HaystackDefinition("^Foo"))); 15 | } 16 | 17 | [TestMethod] 18 | [ExpectedException(typeof(ArgumentException))] 19 | public void TestBadDefConstruction() 20 | { 21 | string[] badDefs = new string[] 22 | { 23 | "^@a", 24 | "^a b", 25 | "^a\n", 26 | "^@", 27 | "a", 28 | "bcd", 29 | }; 30 | foreach (string strID in badDefs) 31 | { 32 | new HaystackDefinition(strID); 33 | } 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/Values/HaystackListTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using ProjectHaystack; 5 | 6 | namespace ProjectHaystackTest 7 | { 8 | [TestClass] 9 | public class HaystackListTests 10 | { 11 | [TestMethod] 12 | public void TestEmpty() 13 | { 14 | Assert.IsTrue(new HaystackList().Equals(new HaystackList(new List()))); 15 | Assert.IsTrue(new HaystackList().Equals(new HaystackList(new HaystackValue[0]))); 16 | Assert.AreEqual(new HaystackList().Count, 0); 17 | Assert.ThrowsException(() => new HaystackList()[0]); 18 | } 19 | 20 | [TestMethod] 21 | public void TestBasics() 22 | { 23 | var hrefTest = new HaystackReference("a"); 24 | var str = new HaystackString("string"); 25 | List items = new List(); 26 | items.Add(hrefTest); 27 | items.Add(str); 28 | 29 | var list = new HaystackList(items); 30 | Assert.AreEqual(list.Count, 2); 31 | Assert.AreEqual(list[0], hrefTest); 32 | Assert.AreEqual(list[1], str); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/Values/HaystackMarkerTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using ProjectHaystack; 3 | 4 | namespace ProjectHaystackTest 5 | { 6 | [TestClass] 7 | public class HaystackMarkerTests 8 | { 9 | [TestMethod] 10 | public void TestEquality() 11 | { 12 | Assert.IsTrue(new HaystackMarker().Equals(new HaystackMarker())); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/Values/HaystackNumberTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using ProjectHaystack; 4 | 5 | namespace ProjectHaystackTest 6 | { 7 | [TestClass] 8 | public class HaystackNumberTests 9 | { 10 | [TestMethod] 11 | public void TestEquality() 12 | { 13 | Assert.IsTrue(new HaystackNumber(2).Equals(new HaystackNumber(2.0, null))); 14 | Assert.IsFalse(new HaystackNumber(2).Equals(new HaystackNumber(2, "%"))); 15 | Assert.IsFalse(new HaystackNumber(2, "%").Equals(new HaystackNumber(2))); 16 | Assert.IsTrue(new HaystackNumber(0).Equals(new HaystackNumber(0.0))); 17 | } 18 | 19 | [TestMethod] 20 | public void TestCompare() 21 | { 22 | Assert.IsTrue(new HaystackNumber(9).CompareTo(new HaystackNumber(11)) < 0); 23 | Assert.IsTrue(new HaystackNumber(-3).CompareTo(new HaystackNumber(-4)) > 0); 24 | Assert.AreEqual(new HaystackNumber(-23).CompareTo(new HaystackNumber(-23)), 0); 25 | } 26 | 27 | [TestMethod] 28 | [ExpectedException(typeof(ArgumentException))] 29 | public void TestBadUnitConstruction() 30 | { 31 | string[] badunitNames = new string[] 32 | { 33 | "foo bar", 34 | "foo,bar" 35 | }; 36 | foreach (string curUnit in badunitNames) 37 | { 38 | new HaystackNumber(123.4, curUnit); 39 | } 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/Values/HaystackReferenceTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using ProjectHaystack; 4 | 5 | namespace ProjectHaystackTest 6 | { 7 | [TestClass] 8 | public class HaystackReferenceTests 9 | { 10 | [TestMethod] 11 | public void TestEquality() 12 | { 13 | Assert.IsTrue(new HaystackReference("foo").Equals(new HaystackReference("foo"))); 14 | Assert.IsTrue(new HaystackReference("foo").Equals(new HaystackReference("foo", "Foo"))); 15 | Assert.IsFalse(new HaystackReference("foo").Equals(new HaystackReference("Foo"))); 16 | } 17 | 18 | [TestMethod] 19 | [ExpectedException(typeof(ArgumentException))] 20 | public void TestBadRefConstruction() 21 | { 22 | string[] badRefs = new string[] 23 | { 24 | "@a", 25 | "a b", 26 | "a\n", 27 | "@" 28 | }; 29 | foreach (string strID in badRefs) 30 | { 31 | new HaystackReference(strID); 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/Values/HaystackRowTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using ProjectHaystack; 6 | 7 | namespace ProjectHaystackTest 8 | { 9 | [TestClass] 10 | public class HaystackRowTests 11 | { 12 | [TestMethod] 13 | public void TestEmpty() 14 | { 15 | var row = BuildRows(Array.Empty(), Array.Empty()).First(); 16 | Assert.IsTrue(row.IsEmpty()); 17 | Assert.AreEqual(row.Count, 0); 18 | Assert.IsFalse(row.ContainsKey("foo")); 19 | } 20 | 21 | [TestMethod] 22 | public void TestCheckedImplicitMissing() 23 | { 24 | var row = BuildRows(Array.Empty(), Array.Empty()).First(); 25 | Assert.ThrowsException(() => row["foo"]); 26 | } 27 | 28 | [TestMethod] 29 | public void TestBasics() 30 | { 31 | var row = BuildRows( 32 | new[] { "id", "site", "geoAddr", "area", "date", "null" }, 33 | new HaystackValue[] { new HaystackReference("aaaa-bbbb"), new HaystackMarker(), new HaystackString("Richmond, Va"), new HaystackNumber(1200, "ft"), new HaystackDate(2000, 12, 3), null }) 34 | .First(); 35 | 36 | // size 37 | Assert.AreEqual(row.Count, 5); 38 | Assert.IsFalse(row.IsEmpty()); 39 | 40 | // configured tags 41 | Assert.IsTrue(row["id"].Equals(new HaystackReference("aaaa-bbbb"))); 42 | Assert.IsTrue(row["site"].Equals(new HaystackMarker())); 43 | Assert.IsTrue(row["geoAddr"].Equals(new HaystackString("Richmond, Va"))); 44 | Assert.IsTrue(row.Get("area").Equals(new HaystackNumber(1200, "ft"))); 45 | Assert.IsTrue(row.Get("date").Equals(new HaystackDate(2000, 12, 3))); 46 | Assert.ThrowsException(() => row.Get("null")); 47 | 48 | // missing tag 49 | Assert.IsFalse(row.ContainsKey("foo")); 50 | Assert.ThrowsException(() => row.Get("foo")); 51 | } 52 | 53 | [TestMethod] 54 | public void TestToArray() 55 | { 56 | var row = BuildRows(new[] { "x", "y" }, new HaystackValue[] { new HaystackMarker(), new HaystackString("str") }).First(); 57 | var array = row.ToArray(); 58 | Assert.AreEqual(2, array.Length); 59 | Assert.AreEqual("x", array[0].Key); 60 | Assert.AreEqual(new HaystackMarker(), array[0].Value); 61 | Assert.AreEqual("y", array[1].Key); 62 | Assert.AreEqual(new HaystackString("str"), array[1].Value); 63 | } 64 | 65 | [TestMethod] 66 | public void TestAdd() 67 | { 68 | var row = BuildRows(new[] { "x", "y" }, new HaystackValue[] { new HaystackMarker(), new HaystackString("y") }).First(); 69 | Assert.ThrowsException(() => row.Add("z", new HaystackMarker())); 70 | } 71 | 72 | [TestMethod] 73 | public void TestRemove() 74 | { 75 | var row = BuildRows(new[] { "x", "y" }, new HaystackValue[] { new HaystackMarker(), new HaystackString("y") }).First(); 76 | Assert.ThrowsException(() => row.Remove("y")); 77 | } 78 | 79 | public static IEnumerable BuildRows(ICollection cols, params HaystackValue[][] rows) 80 | { 81 | var grid = new HaystackGrid(); 82 | foreach (var col in cols) 83 | { 84 | grid.AddColumn(col); 85 | } 86 | foreach (var row in rows) 87 | { 88 | grid.AddRow(row); 89 | } 90 | return grid.Rows; 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/Values/HaystackStringTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using ProjectHaystack; 3 | 4 | namespace ProjectHaystackTest 5 | { 6 | [TestClass] 7 | public class HaystackStringTests 8 | { 9 | [TestMethod] 10 | public void TestEquality() 11 | { 12 | Assert.IsTrue(new HaystackString("a").Equals(new HaystackString("a"))); 13 | Assert.IsFalse(new HaystackString("a").Equals(new HaystackString("b"))); 14 | Assert.IsTrue(new HaystackString("").Equals(new HaystackString(""))); 15 | } 16 | 17 | [TestMethod] 18 | public void TestCompare() 19 | { 20 | Assert.IsTrue(new HaystackString("abc").CompareTo(new HaystackString("z")) < 0); 21 | Assert.AreEqual(new HaystackString("Foo").CompareTo(new HaystackString("Foo")), 0); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/Values/HaystackTimeTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using ProjectHaystack; 4 | 5 | namespace ProjectHaystackTest 6 | { 7 | [TestClass] 8 | public class HaystackTimeTests 9 | { 10 | [TestMethod] 11 | public void TestEquality() 12 | { 13 | Assert.IsTrue(new HaystackTime(new TimeSpan(0, 1, 2, 3, 4)).Equals(new HaystackTime(new TimeSpan(0, 1, 2, 3, 4)))); 14 | Assert.IsFalse(new HaystackTime(new TimeSpan(0, 1, 2, 3, 4)).Equals(new HaystackTime(new TimeSpan(0, 9, 2, 3, 4)))); 15 | Assert.IsFalse(new HaystackTime(new TimeSpan(0, 1, 2, 3, 4)).Equals(new HaystackTime(new TimeSpan(0, 1, 9, 3, 4)))); 16 | Assert.IsFalse(new HaystackTime(new TimeSpan(0, 1, 2, 3, 4)).Equals(new HaystackTime(new TimeSpan(0, 1, 2, 9, 9)))); 17 | } 18 | 19 | [TestMethod] 20 | public void TestCompare() 21 | { 22 | Assert.IsTrue(new HaystackTime(new TimeSpan(0, 0, 0, 0, 0)).CompareTo(new HaystackTime(new TimeSpan(0, 0, 0, 0, 9))) < 0); 23 | Assert.IsTrue(new HaystackTime(new TimeSpan(0, 0, 0, 0, 0)).CompareTo(new HaystackTime(new TimeSpan(0, 0, 0, 1, 0))) < 0); 24 | Assert.IsTrue(new HaystackTime(new TimeSpan(0, 0, 1, 0, 0)).CompareTo(new HaystackTime(new TimeSpan(0, 0, 0, 0, 0))) > 0); 25 | Assert.IsTrue(new HaystackTime(new TimeSpan(0, 0, 0, 0, 0)).CompareTo(new HaystackTime(new TimeSpan(0, 2, 0, 0, 0))) < 0); 26 | Assert.AreEqual(new HaystackTime(new TimeSpan(0, 2, 0, 0, 0)).CompareTo(new HaystackTime(new TimeSpan(0, 2, 0, 0, 0))), 0); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/Values/HaystackTimeZoneTests.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using ProjectHaystack; 4 | 5 | namespace ProjectHaystackTest 6 | { 7 | [TestClass] 8 | public class HaystackTimeZoneTests 9 | { 10 | [TestMethod] 11 | public void Make_utc() 12 | { 13 | var tz = new HaystackTimeZone("UTC"); 14 | Assert.IsTrue(new[] { "UTC", "Etc/UTC" }.Contains(tz.TimeZoneInfo.Id)); 15 | } 16 | 17 | [TestMethod] 18 | public void Make_sidney() 19 | { 20 | var tz = new HaystackTimeZone("Sydney"); 21 | Assert.IsTrue(new[] { "AUS Eastern Standard Time", "Australia/Sydney" }.Contains(tz.TimeZoneInfo.Id)); 22 | } 23 | 24 | [TestMethod] 25 | public void TestTz_NewYork() 26 | { 27 | VerifyTz("New_York", "Eastern Standard Time", "America/New_York"); 28 | } 29 | 30 | [TestMethod] 31 | public void TestTz_Chicago() 32 | { 33 | VerifyTz("Chicago", "Central Standard Time", "America/Chicago"); 34 | } 35 | 36 | [TestMethod] 37 | public void TestTz_Phoenix() 38 | { 39 | VerifyTz("Phoenix", "US Mountain Standard Time", "America/Phoenix"); 40 | } 41 | 42 | [TestMethod] 43 | public void TestTz_London() 44 | { 45 | VerifyTz("London", "GMT Standard Time", "Europe/London"); 46 | } 47 | 48 | [TestMethod] 49 | public void TestTz_UTC() 50 | { 51 | VerifyTz("UTC", "UTC", "Etc/UTC"); 52 | } 53 | 54 | [TestMethod] 55 | public void TestTz_GMT() 56 | { 57 | VerifyTz("GMT", "UTC", "GMT"); 58 | } 59 | 60 | [TestMethod] 61 | public void TestTz_Rel() 62 | { 63 | VerifyTz("Rel", "UTC", "GMT"); // GMT 64 | } 65 | 66 | private void VerifyTz(string name, params string[] dntzIds) 67 | { 68 | var tz = new HaystackTimeZone(name); 69 | // Ignore issues with locally installed timezones. 70 | if (tz == null) 71 | { 72 | return; 73 | } 74 | var dntz = tz.TimeZoneInfo; 75 | Assert.AreEqual(tz.Name, name); 76 | Assert.IsTrue(dntzIds.Contains(dntz.Id), $"{dntz.Id} not in [{string.Join(", ", dntzIds)}]"); 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/Values/HaystackUriTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using ProjectHaystack; 3 | 4 | namespace ProjectHaystackTest 5 | { 6 | [TestClass] 7 | public class HaystackUriTests 8 | { 9 | [TestMethod] 10 | public void TestEquality() 11 | { 12 | Assert.IsTrue(new HaystackUri("a").Equals(new HaystackUri("a"))); 13 | Assert.IsFalse(new HaystackUri("a").Equals(new HaystackUri("b"))); 14 | Assert.IsTrue(new HaystackUri("") == new HaystackUri("")); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/Values/HaystackXStringTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using ProjectHaystack; 4 | 5 | namespace ProjectHaystackTest 6 | { 7 | [TestClass] 8 | public class HaystackXStringTests 9 | { 10 | [TestMethod] 11 | public void TestTypeStartsWithUpper() 12 | { 13 | new HaystackXString("a", "Type"); 14 | Assert.ThrowsException(() => new HaystackXString("a", "type")); 15 | } 16 | 17 | [TestMethod] 18 | public void TestTypeContainsValidCharacters() 19 | { 20 | new HaystackXString("a", "TyP0_s"); 21 | Assert.ThrowsException(() => new HaystackXString("a", "T.")); 22 | Assert.ThrowsException(() => new HaystackXString("a", "T,")); 23 | } 24 | 25 | [TestMethod] 26 | public void TestEquality() 27 | { 28 | Assert.IsTrue(new HaystackXString("a", "Type").Equals(new HaystackXString("a", "Type"))); 29 | Assert.IsFalse(new HaystackXString("a", "X").Equals(new HaystackXString("b", "X"))); 30 | Assert.IsTrue(new HaystackXString("", "X").Equals(new HaystackXString("", "X"))); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/io/HZincReaderTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using ProjectHaystack; 3 | using ProjectHaystack.io; 4 | 5 | namespace ProjectHaystackTest.io 6 | { 7 | [TestClass] 8 | public class HZincReaderTests 9 | { 10 | [TestMethod] 11 | public void readGrid_withTagDef() 12 | { 13 | var reader = new ZincReader( 14 | @"ver:""3.0"" 15 | id,def,doc,mod 16 | @p:struktonLibrary:r:25b81501-75003ad2 ""struktonActivePointOnly"",^struktonActivePointOnly,""Import only active points"",2020-01-20T07:36:33.162Z"); 17 | var grid = reader.ReadValue(); 18 | Assert.IsTrue(grid.Row(0).Get("def") is HaystackDefinition); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/io/TrioReaderTests.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using ProjectHaystack; 4 | using ProjectHaystack.io; 5 | 6 | namespace ProjectHaystackTest.io 7 | { 8 | [TestClass] 9 | public class TrioReaderTests 10 | { 11 | [TestMethod] 12 | public void ReadEntities_TwoEntities_IsValid() 13 | { 14 | // Arrange. 15 | var trio = @"dis: ""Site 1"" 16 | site 17 | area: 3702ft² 18 | geoAddr: ""100 Main St, Richmond, VA"" 19 | geoCoord: C(37.5458,-77.4491) 20 | strTag: OK if unquoted if only safe chars 21 | summary: 22 | This is a string value which spans multiple 23 | lines with two or more space characters 24 | --- 25 | name: ""Site 2"" 26 | site 27 | summary: 28 | Entities are separated by one or more dashes"; 29 | var reader = new TrioReader(trio); 30 | 31 | // Act. 32 | var entities = reader.ReadEntities().ToArray(); 33 | 34 | // Assert. 35 | Assert.AreEqual(2, entities.Length); 36 | Assert.AreEqual(new HaystackMarker(), entities[0]["site"]); 37 | Assert.AreEqual(new HaystackString("Entities are separated by one or more dashes"), entities[1]["summary"]); 38 | } 39 | 40 | [TestMethod] 41 | public void ReadEntities_NestedZincGrid_IsValid() 42 | { 43 | // Arrange. 44 | var trio = @"// Trio 45 | type:list 46 | val:[1,2,3] 47 | --- 48 | type:dict 49 | val:{ dis:""Dict!"" foo} 50 | --- 51 | type:grid 52 | val:Zinc: 53 | ver:""3.0"" 54 | b,a 55 | 20,10"; 56 | var reader = new TrioReader(trio); 57 | 58 | // Act. 59 | var entities = reader.ReadEntities().ToArray(); 60 | 61 | // Assert. 62 | Assert.AreEqual(3, entities.Length); 63 | Assert.AreEqual(new HaystackString("list"), entities[0]["type"]); 64 | Assert.IsTrue(entities[1]["val"] is HaystackDictionary); 65 | Assert.IsTrue(entities[2]["val"] is HaystackGrid); 66 | Assert.AreEqual(10, (((HaystackGrid)entities[2]["val"]).Row(0).Get("a") as HaystackNumber).Value); 67 | } 68 | 69 | [TestMethod] 70 | public void ReadEntities_NestedTrioGrid_IsValid() 71 | { 72 | // Arrange. 73 | var trio = @"// Trio 74 | type:list 75 | val:[1,2,3] 76 | --- 77 | type:dict 78 | val:{ dis:""Dict!"" foo} 79 | --- 80 | type:list 81 | val: Trio: 82 | b: 20 83 | a: 10"; 84 | var reader = new TrioReader(trio); 85 | 86 | // Act. 87 | var entities = reader.ReadEntities().ToArray(); 88 | 89 | // Assert. 90 | Assert.AreEqual(3, entities.Length); 91 | Assert.AreEqual(new HaystackString("list"), entities[0]["type"]); 92 | Assert.IsTrue(entities[1]["val"] is HaystackDictionary); 93 | Assert.IsTrue(entities[2]["val"] is HaystackDictionary); 94 | Assert.AreEqual(10, ((HaystackNumber)((HaystackDictionary)entities[2]["val"])["a"]).Value); 95 | } 96 | 97 | [TestMethod] 98 | public void ToGrid_TwoEntities_IsValid() 99 | { 100 | // Arrange. 101 | var trio = @"dis: ""Site 1"" 102 | site 103 | area: 3702ft² 104 | geoAddr: ""100 Main St, Richmond, VA"" 105 | geoCoord: C(37.5458,-77.4491) 106 | strTag: OK if unquoted if only safe chars 107 | summary: 108 | This is a string value which spans multiple 109 | lines with two or more space characters 110 | --- 111 | name: ""Site 2"" 112 | site 113 | summary: 114 | Entities are separated by one or more dashes"; 115 | var reader = new TrioReader(trio); 116 | 117 | // Act. 118 | var grid = reader.ToGrid(); 119 | 120 | // Assert. 121 | Assert.AreEqual(2, grid.Rows.Count()); 122 | Assert.AreEqual(8, grid.Columns.Count()); 123 | Assert.AreEqual(new HaystackMarker(), grid.Row(0).Get("site")); 124 | Assert.AreEqual(new HaystackString("Entities are separated by one or more dashes"), grid.Row(1).Get("summary")); 125 | } 126 | } 127 | } -------------------------------------------------------------------------------- /ProjectHaystackTest/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /build-system/unix-pr-validation.yml: -------------------------------------------------------------------------------- 1 | trigger: 2 | branches: 3 | include: 4 | - master 5 | 6 | name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r) 7 | 8 | stages: 9 | - stage: Build 10 | displayName: "Build and test libraries" 11 | jobs: 12 | - job: BuildTestPublish 13 | pool: 14 | vmImage: 'ubuntu-latest' 15 | workspace: 16 | clean: all 17 | steps: 18 | - checkout: self 19 | displayName: "Clean source checkout" 20 | clean: true 21 | - task: UseDotNet@2 22 | displayName: "Use .NET Core sdk" 23 | inputs: 24 | packageType: sdk 25 | installationPath: $(Agent.ToolsDirectory)/dotnet 26 | useGlobalJson: true 27 | 28 | - task: gittools.gittools.setup-gitversion-task.gitversion/setup@0 29 | displayName: "GitVersion: Setup" 30 | inputs: 31 | versionSpec: '5.x' 32 | 33 | - task: gittools.gittools.execute-gitversion-task.gitversion/execute@0 34 | displayName: "GitVersion: Determine version information" 35 | inputs: 36 | useConfigFile: true 37 | configFilePath: 'GitVersion.yml' 38 | 39 | - task: bleddynrichards.Assembly-Info-Task.Assembly-Info-NetCore.Assembly-Info-NetCore@2 40 | displayName: "Set Assembly Manifest Data" 41 | inputs: 42 | InsertAttributes: true 43 | Company: Strukton Worksphere 44 | Copyright: "Copyright © $(date:YYYY) Strukton Worksphere" 45 | VersionNumber: "$(GitVersion.AssemblySemVer)" 46 | FileVersionNumber: "$(GitVersion.AssemblySemFileVer)" 47 | InformationalVersion: "$(GitVersion.InformationalVersion)" 48 | PackageVersion: "$(GitVersion.NuGetVersion)" 49 | 50 | - task: DotNetCoreCLI@2 51 | displayName: "Restore dependencies for all projects" 52 | inputs: 53 | command: restore 54 | projects: "**/*.csproj" 55 | noCache: true 56 | 57 | - task: DotNetCoreCLI@2 58 | displayName: "Pack the package ProjectHaystack" 59 | continueOnError: false 60 | inputs: 61 | command: custom 62 | custom: pack 63 | arguments: "--configuration Release --no-restore --output $(Build.ArtifactStagingDirectory)/ProjectHaystack" 64 | projects: "**/ProjectHaystack.csproj" 65 | 66 | - task: DotNetCoreCLI@2 67 | displayName: "Run tests" 68 | continueOnError: false 69 | inputs: 70 | command: test 71 | arguments: "--configuration Release --no-restore --output $(Build.ArtifactStagingDirectory)/ProjectHaystack" 72 | projects: "**/ProjectHaystack.csproj" 73 | 74 | - task: PublishBuildArtifacts@1 75 | condition: ne(variables['Build.Reason'], 'PullRequest') 76 | displayName: "Publish Artifact: ProjectHaystack" 77 | continueOnError: false 78 | inputs: 79 | PathtoPublish: "$(Build.ArtifactStagingDirectory)/ProjectHaystack" 80 | ArtifactName: "ProjectHaystack" 81 | 82 | - ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: 83 | - stage: PushToFeed 84 | displayName: "Push to feed" 85 | condition: succeeded() 86 | jobs: 87 | - deployment: PublishToFeed 88 | displayName: "Publish libraries to feed" 89 | environment: "NuGetFeed" 90 | pool: 91 | vmImage: 'ubuntu-latest' 92 | workspace: 93 | clean: all 94 | strategy: 95 | runOnce: 96 | deploy: 97 | steps: 98 | - download: current 99 | - task: NuGetToolInstaller@0 100 | displayName: "Use latest NuGet" 101 | continueOnError: false 102 | - task: NuGetCommand@2 103 | displayName: "Release to feed" 104 | inputs: 105 | command: push 106 | packagesToPush: "$(Pipeline.Workspace)/ProjectHaystack/*.nupkg" 107 | NuGetFeedType: "external" 108 | publishFeedCredentials: "NuGet.org" 109 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "8.0.300", 4 | "rollForward": "latestPatch" 5 | } 6 | } 7 | --------------------------------------------------------------------------------