11

I ran into an interesting problem today where my tests were failing consistently on the build machine when they worked just fine on my machine even using the same configuration. When I looked at the differences output by Assert.AreEqual in the failure dump, I couldn't see anything different. After a bunch of investigation, I came to find out that the verbatim string in the test case source code (which spanned multiple lines) was using CRLF on my machine, but using LF on the build machine, causing comparisons of that string with a generated string to fail. The culprit turned out to be inconsistent Git settings on the two systems, with the build system automatically converting CRLF sequences to just LF.

Does the C# specification say anything about how line breaks in verbatim strings should be interpreted (perhaps using Environment.Newline, or at least something consistent)? This seems like a problem that could bite lots of people in very hard to diagnose and hard to fix ways, especially with .NET Standard. For example, if you have a .NET Standard project, and have team members on both Linux and Windows, this is likely to bite either the Linux team members or the Windows team members.

James
  • 3,551
  • 1
  • 28
  • 38
  • have you looked at: https://stackoverflow.com/questions/170961/whats-the-best-crlf-carriage-return-line-feed-handling-strategy-with-git?rq=1 – DaniDev Jan 10 '18 at 22:07
  • 1
    you can config how git behaves. just make build machine check out using LF and you will be fine – Steve Jan 10 '18 at 22:18
  • @DaniDev, I get that, but even with the settings set properly for each platform, the fact that the actual values for the same string literal are different on different platforms seems like an extraordinarily bad idea. Not having consistency here basically means that you shouldn't ever use verbatim string literals in .NET Standard code unless you force all your team members to use the same line break system on their local systems, not just in source control. – James Jan 10 '18 at 22:24
  • @Steve, yes I see that *now*, but having the actual value of a literal string change based on source control settings seems like a big problem. – James Jan 10 '18 at 22:26
  • @Steve, my build machine *is* set to use LF. It's my own windows machine that isn't (because *CRLF* is the default on Windows). At the very least, having the actual runtime value of a literal vary based on source control settings is a trap that's extremely difficult to diagnose. – James Jan 10 '18 at 22:32
  • @Pac0, I think you missed the gist of the question. I'm talking about how the C# compiler interprets verbatim string literals. If it used Environment.NewLine, it would be at least be understandable, but it doesn't even do that. It just reads the raw bytes from the source file. *I* have no control over that. – James Jan 10 '18 at 22:48
  • 1
    "@DaniDev, I get that "... Not sure which "that" you are refereing to? Did you read the Accepted answer seems like it's a good strategy although I cant say I have tried it myself. It says: " Git allows you to set the line ending properties for a repo directly using the text attribute in the .gitattributes file. This file is committed into the repo and overrides the core.autocrlf setting, allowing you to ensure consistent behaviour for all users regardless of their git settings." – DaniDev Jan 10 '18 at 22:51
  • @DaniDev consistent settings across files in the master repository are irrelevant. The problem is that different developers with the "same" code get different values for the same string literal. – James Jan 10 '18 at 23:00

2 Answers2

5

The spec addresses this by not addressing it:

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/lexical-structure

In a verbatim string literal, the characters between the delimiters are interpreted verbatim, the only exception being a quote_escape_sequence.

Since no exception is made for line endings, you get whatever line endings were used in the source file. As you found out.

  • 1
    `you get whatever line endings were used in the source file` Well then shouldn't those characters be `\r\n` since the source was created on his machine? – Kenneth K. Jan 10 '18 at 22:14
  • 3
    @KennethK. If the OP has configured source control in such a way that CRLFs are replaced by LFs on other machines (and the OP has done just that), then no. –  Jan 10 '18 at 22:15
  • 1
    Thinking about it, I suspect any configuration setting or hard-coded default would introduce more problems than it would solve. Best to take the path of least interference as they have done so that your quest ends with the finding of the different source code rather than having to seek out a configuration value or documented standard. I for one would not rely on source code format and would always only insert newlines explicitly with escape sequences or Environment.NewLine. – BlueMonkMN Jan 10 '18 at 23:27
  • @BlueMonkMN In very common uses of multi-line verbatim string literals, it doesn't matter which style of line endings are used, because either style has the exact same effect. In those cases, I wouldn't worry about it. Otherwise, agreed. –  Jan 10 '18 at 23:54
0

This solution based on the Git Help documentation may help ensure consistency regardless of each Git instance's setting.

As per the documentation in https://help.github.com/articles/dealing-with-line-endings/

Optionally, you can configure the way Git manages line endings on a per-repository basis by configuring a special .gitattributes file. This file is committed into the repository and overrides an individual's core.autocrlf setting, ensuring consistent behavior for all users, regardless of their Git settings.

DaniDev
  • 2,471
  • 2
  • 22
  • 29
  • The git settings only ensure that the *master* copy is consistent. Each developer still ends up with code that has different characters for the same string literal, which can cause subtle problems. – James Jan 10 '18 at 22:59
  • " Each developer still ends up with code that has different characters " are you referring to the resulting code once a developer has interacted/modified with it in their development environment? Or Maybe as you mentioned "build system...." it would seem to me that you would only build off of a master copy, no? – DaniDev Jan 10 '18 at 23:06
  • actually I'm not sure I understand the documentation you've referred to. Does "consistent behavior for all users" mean that the files in the master copy are made consistent, the files on my local system are always made consistent with the norms for that platform, or something else? – James Jan 10 '18 at 23:10
  • My understanding of the documentation is that by "configuring a special .gitattributes file." which is part of the git package it will override the individual setting on each machine's "core.autocrlf" so that it will interprate the line break consistently? maybe this is not address the issue you are experiencing but it seemed to me like it worth a shot? – DaniDev Jan 10 '18 at 23:15
  • Hmm. That may be what it means (not very well worded documentation). Even though that may well solve the problem for me for the moment, it still seems like a big issue--if a Linux developer's code editor were to change the line breaks for a source file they edited, they could still have hard-to-diagnose problems until they checked in and git fixed it up for them. Seems like a bad design. – James Jan 10 '18 at 23:23
  • Understood! it is problematic. But the line break reinterpretation across (development) system is not unique (to Git), and has bit many developers in the ass (not ashamed to admit, myself included) At least Git has offered a solution in as much as it can control. Hard to control when it leaves the (Git) environment. – DaniDev Jan 10 '18 at 23:37
  • 1
    @James If you want no LF<=>CRLF translation, that's one of the things you can set in `.gitattributes`. That way, if a Linux developer's code editor were to change the line breaks from CRLF to LF (far less likely than a Windows developer's code editor changing LF to CRLF, mind you!), at least `git diff` would show every line as modified. –  Jan 11 '18 at 11:35