Menu

[r2035]: / trunk / Src / UTestUnit.pas  Maximize  Restore  History

Download this file

182 lines (159 with data), 5.4 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
{
* UTestUnit.pas
*
* Implements a class that generates Pascal units for use in test compiling
* snippets.
*
* $Rev$
* $Date$
*
* ***** BEGIN LICENSE BLOCK *****
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The Original Code is UTestUnit.pas
*
* The Initial Developer of the Original Code is Peter Johnson
* (http://www.delphidabbler.com/).
*
* Portions created by the Initial Developer are Copyright (C) 2006-2012 Peter
* Johnson. All Rights Reserved.
*
* Contributor(s)
* NONE
*
* ***** END LICENSE BLOCK *****
}
unit UTestUnit;
interface
uses
// Project
DB.USnippet;
type
/// <summary>
/// Class that generates Pascal units for use in test compiling snippets.
/// </summary>
TTestUnit = class(TObject)
strict private
var
/// <summary>Reference to snippet for which test unit is required.
/// </summary>
fSnippet: TSnippet;
/// <summary>Generates name of test unit, based on snippet being tested.
/// </summary>
/// <remarks>Returned unit name contains only valid ASCII characters. Any
/// invalid characters are replaced with '_'.</remarks>
function UnitName: string;
/// <summary>Builds and returns fully specified unit file name.</summary>
function UnitFileName: string;
public
/// <summary>Sets up object to create test unit for given snippet.
/// </summary>
constructor Create(const Snippet: TSnippet);
/// <summary>Generates source code of test unit.</summary>
function GenerateUnitSource: string;
/// <summary>Saves generated source to file.</summary>
/// <param name="FileName">string [out] Set to name of unit file. Base name
/// is name of unit.</param>
/// <remarks>
/// <para>Base file name contains only valid ASCII characters.</para>
/// <para>File is saved in default ANSI encoding unless source code
/// contains any characters not valid in default ANSI code page. In this
/// case file is saved with UTF-8 encoding.</para>
/// </remarks>
procedure SaveUnit(out FileName: string);
end;
implementation
uses
// Delphi
SysUtils,
// Project
DB.USnippetKind, UEncodings, UIOUtils, USourceGen, USystemInfo, UUnitAnalyser,
UUtils;
{ TTestUnit }
constructor TTestUnit.Create(const Snippet: TSnippet);
begin
Assert(Assigned(Snippet), ClassName + '.Create: Snippet is nil');
inherited Create;
fSnippet := Snippet;
end;
function TTestUnit.GenerateUnitSource: string;
begin
if fSnippet.Kind <> skUnit then
begin
with TSourceGen.Create do
try
IncludeSnippet(fSnippet);
// Must use Self.UnitName below for Delphis that defined TObject.UnitName
// otherwise the TObject version is used.
Result := UnitAsString(Self.UnitName);
finally
Free;
end;
end
else
Result := fSnippet.SourceCode;
end;
procedure TTestUnit.SaveUnit(out FileName: string);
var
SourceCode: string;
Encoding: TEncoding;
begin
FileName := UnitFileName;
SourceCode := GenerateUnitSource;
// If all of the source code is supported by default ANSI code page we use
// that to write file, otherwise we use UTF-8.
// Preference for default ANSI encoding is because early Delphis can only read
// source code files in this format. Later versions that can handle unicode
// characters in units also support UTF-8 format source code files.
Encoding := TUnitAnalyser.RequiredEncoding(SourceCode);
try
TFileIO.WriteAllText(FileName, SourceCode, Encoding, True);
finally
TEncodingHelper.FreeEncoding(Encoding);
end;
end;
function TTestUnit.UnitFileName: string;
const
cPasExt = '.pas'; // file extension for Pascal unit:
begin
// Unit file name is in temp folder
Result := IncludeTrailingPathDelimiter(TSystemFolders.Temp)
+ UnitName + cPasExt;
end;
function TTestUnit.UnitName: string;
const
cUnitPrefix = 'U_'; // unit file name prefix
var
I: Integer;
Ch: Char;
begin
if fSnippet.Kind = skUnit then
Exit(TUnitAnalyser.UnitName(fSnippet.SourceCode));
// Unit name is same as Snippet being tested, but with prefix to make unique
Result := cUnitPrefix + fSnippet.Name;
// We ensure only ASCII characters are used in unit name. Any unsuitable
// characters are replaced by underscore.
// This is done because unit name is also used as unit file name. If we took
// no action would could have a Unicode file name. Earlier versions of Delphi
// can't cope with Unicode file names and claim the file can't be found. Some
// compilers like Delphi 2006 that can handle non-ANSI characters in source
// code still cannot handle those characters in the file name.
// Some valid ANSI characters are not handled by some compilers, hence we have
// fallen back to ASCII.
for I := 1 to Length(Result) do
begin
Ch := Result[I];
if not EncodingSupportsString(Ch, TEncoding.ASCII) then
Result[I] := '_';
end;
end;
end.
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.